diff --git a/web/e2e/utils/process.js b/web/e2e/utils/process.js new file mode 100644 index 0000000..93e0c26 --- /dev/null +++ b/web/e2e/utils/process.js @@ -0,0 +1,34 @@ +import { spawn } from 'node:child_process'; + +export function startProcess(command, args, options = {}) { + const child = spawn(command, args, { + cwd: options.cwd, + env: { ...process.env, ...(options.env || {}) }, + shell: process.platform === 'win32', + stdio: ['ignore', 'pipe', 'pipe'], + }); + + const output = []; + child.stdout.on('data', (chunk) => output.push(chunk.toString())); + child.stderr.on('data', (chunk) => output.push(chunk.toString())); + + child.once('exit', (code) => { + if (code !== null && code !== 0) { + output.push(`\nprocess exited with code ${code}\n`); + } + }); + + return { child, output }; +} + +export async function stopProcess(child) { + if (!child || child.killed) return; + await new Promise((resolve) => { + child.once('exit', resolve); + child.kill(process.platform === 'win32' ? undefined : 'SIGTERM'); + setTimeout(() => { + if (!child.killed) child.kill('SIGKILL'); + resolve(); + }, 5000).unref(); + }); +} diff --git a/web/e2e/utils/wait.js b/web/e2e/utils/wait.js new file mode 100644 index 0000000..dae9661 --- /dev/null +++ b/web/e2e/utils/wait.js @@ -0,0 +1,19 @@ +export async function waitForHttp(url, options = {}) { + const timeoutMs = options.timeoutMs || 60000; + const intervalMs = options.intervalMs || 500; + const start = Date.now(); + let lastError; + + while (Date.now() - start < timeoutMs) { + try { + const response = await fetch(url, { cache: 'no-store' }); + if (response.ok) return response; + lastError = new Error(`HTTP ${response.status}`); + } catch (error) { + lastError = error; + } + await new Promise((resolve) => setTimeout(resolve, intervalMs)); + } + + throw new Error(`Timed out waiting for ${url}: ${lastError?.message || 'no response'}`); +}