Hello from MCP server
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,
};
}