Hello from MCP server

List Files | Just Commands | Repo | Logs

โ† back |
import { spawn } from "child_process";
import getPort from "get-port";
import path from "path";
import { rmSync } from "fs";
import fs from "fs";

// Reuse backend startup logic from API tests
async function buildGoProject() {
  const goBinary = "go";
  const projectDir = path.resolve("../../backend");
  const outputPath = path.join(projectDir, "./", "pricebook-platform");

  return new Promise((resolve, reject) => {
    const build = spawn(goBinary, ["build", "-o", outputPath], {
      cwd: projectDir,
      stdio: "inherit",
    });

    build.on("exit", (code) => {
      if (code === 0) {
        console.log(`โœ… Backend build complete at ${outputPath}`);
        resolve();
      } else {
        reject(new Error(`โŒ Backend build failed with exit code ${code}`));
      }
    });
  });
}

async function buildFrontend(backendUrl) {
  const frontendDir = path.resolve("../../frontend");

  return new Promise((resolve, reject) => {
    console.log(`๐Ÿ”จ Building frontend with backend URL: ${backendUrl}`);

    // Set the backend URL as environment variable for the build
    const env = {
      ...process.env,
      VITE_API_HOST: backendUrl
    };

    const build = spawn("npm", ["run", "build"], {
      cwd: frontendDir,
      stdio: "inherit",
      env: env
    });

    build.on("exit", (code) => {
      if (code === 0) {
        console.log("โœ… Frontend build complete");
        resolve();
      } else {
        reject(new Error(`โŒ Frontend build failed with exit code ${code}`));
      }
    });
  });
}

async function startPocketBase() {
  const pbPath = path.resolve("../../backend/pricebook-platform");
  const port = await getPort();
  const testDir = path.resolve("../../backend/browser_test_data");

  // Clean up any previous test data
  rmSync(testDir, { recursive: true, force: true });

  console.log(`๐Ÿš€ Starting PocketBase on port ${port}`);

  // Create superuser before server starts
  const upsert = spawn(pbPath, [
    "--dir",
    testDir,
    "superuser",
    "upsert",
    "admin@example.com",
    "0123456789",
  ]);

  await new Promise((res) => upsert.on("exit", res));

  // Create log directory if it doesn't exist
  const logDir = path.resolve("../../logs");
  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir, { recursive: true });
  }

  const logFile = path.resolve("../../logs/browser-test-backend.log");
  const logStream = fs.createWriteStream(logFile, { flags: "a" });

  const pbProcess = spawn(
    pbPath,
    ["serve", "--http", `127.0.0.1:${port}`, "--dir", testDir, "--dev"],
    {
      stdio: ["ignore", "pipe", "pipe"],
    },
  );

  // Redirect stdout and stderr to log file
  pbProcess.stdout.pipe(logStream);
  pbProcess.stderr.pipe(logStream);

  // Wait briefly for PocketBase to be ready
  await new Promise((resolve) => setTimeout(resolve, 2000));

  return { port, testDir, process: pbProcess, logStream };
}

async function startFrontend() {
  const frontendDir = path.resolve("../../frontend");
  const port = await getPort();

  console.log(`๐Ÿš€ Starting frontend preview server on port ${port}`);

  // Create log file for frontend
  const logFile = path.resolve("../../logs/browser-test-frontend.log");
  const logStream = fs.createWriteStream(logFile, { flags: "a" });

  const frontendProcess = spawn("npm", ["run", "preview", "--", "--port", port.toString(), "--host"], {
    cwd: frontendDir,
    stdio: ["ignore", "pipe", "pipe"],
  });

  // Redirect stdout and stderr to log file
  frontendProcess.stdout.pipe(logStream);
  frontendProcess.stderr.pipe(logStream);

  // Wait for frontend to be ready
  await new Promise((resolve) => setTimeout(resolve, 3000));

  return { port, process: frontendProcess, logStream };
}

export async function setupTestEnvironment() {
  console.log("๐Ÿ—๏ธ  Setting up isolated test environment...");

  try {
    // Build backend first
    await buildGoProject();

    // Start backend to get the URL
    const backend = await startPocketBase();
    const backendUrl = `http://127.0.0.1:${backend.port}`;

    // Build frontend with the correct backend URL
    await buildFrontend(backendUrl);

    // Start frontend
    const frontend = await startFrontend();

    const environment = {
      backendUrl: `http://127.0.0.1:${backend.port}`,
      frontendUrl: `http://127.0.0.1:${frontend.port}`,
      backend,
      frontend,
    };

    console.log(`โœ… Test environment ready:`);
    console.log(`   Backend:  ${environment.backendUrl}`);
    console.log(`   Frontend: ${environment.frontendUrl}`);

    return environment;
  } catch (error) {
    console.error("โŒ Failed to setup test environment:", error);
    throw error;
  }
}

export async function teardownTestEnvironment(environment) {
  console.log("๐Ÿงน Tearing down test environment...");

  if (environment?.backend?.process) {
    environment.backend.process.kill();
    environment.backend.logStream?.end();
  }

  if (environment?.frontend?.process) {
    environment.frontend.process.kill();
    environment.frontend.logStream?.end();
  }

  // Clean up test database
  if (environment?.backend?.testDir) {
    try {
      rmSync(environment.backend.testDir, { recursive: true, force: true });
    } catch (error) {
      console.warn("Warning: Could not clean up test directory:", error.message);
    }
  }

  console.log("โœ… Test environment cleaned up");
}

// Global environment storage for tests
export let globalTestEnvironment = null;

export function setGlobalTestEnvironment(env) {
  globalTestEnvironment = env;
}

export function getTestUrls() {
  if (!globalTestEnvironment) {
    throw new Error("Test environment not initialized. Make sure globalSetup has run.");
  }
  return {
    backendUrl: globalTestEnvironment.backendUrl,
    frontendUrl: globalTestEnvironment.frontendUrl,
  };
}