import { spawn, spawnSync } from 'node:child_process'; const baseUrl = 'http://127.0.0.1:4300'; const isWindows = process.platform === 'win32'; const specFile = process.argv[2] || 'e2e/ip-operator-workbench.spec.ts'; let serverProcess = null; async function main() { const alreadyRunning = await isServerReady(); if (!alreadyRunning) { const { command, args } = commandFor('npm run start -- --host 127.0.0.1 --port 4300', 'npm', [ 'run', 'start', '--', '--host', '127.0.0.1', '--port', '4300', ]); serverProcess = spawn(command, args, { stdio: 'inherit', shell: false, }); await waitForServer(); } const code = await runPlaywright(); cleanupServer(); process.exit(code); } async function isServerReady() { try { const response = await fetch(baseUrl); return response.ok; } catch { return false; } } async function waitForServer() { const startedAt = Date.now(); while (Date.now() - startedAt < 120_000) { if (await isServerReady()) return; await new Promise((resolve) => setTimeout(resolve, 1000)); } cleanupServer(); throw new Error(`Angular dev server did not become ready at ${baseUrl}`); } function runPlaywright() { return new Promise((resolve) => { const { command, args } = commandFor(`npx playwright test ${specFile}`, 'npx', [ 'playwright', 'test', specFile, ]); const child = spawn(command, args, { stdio: 'inherit', shell: false, }); child.on('close', (code) => resolve(code ?? 1)); }); } function commandFor(windowsCommand, command, args) { if (!isWindows) return { command, args }; return { command: 'cmd.exe', args: ['/d', '/s', '/c', windowsCommand] }; } function cleanupServer() { if (!serverProcess?.pid) return; if (isWindows) { spawnSync('taskkill', ['/pid', String(serverProcess.pid), '/t', '/f'], { stdio: 'ignore' }); } else { serverProcess.kill('SIGTERM'); } serverProcess = null; } process.on('SIGINT', () => { cleanupServer(); process.exit(130); }); process.on('SIGTERM', () => { cleanupServer(); process.exit(143); }); main().catch((error) => { cleanupServer(); console.error(error); process.exit(1); });