import { spawn } from 'node:child_process'; const truthy = (value) => { if (!value) return false; return ['1', 'true', 'yes', 'on'].includes(String(value).trim().toLowerCase()); }; const shouldSkipDocker = truthy(process.env.PULSE_E2E_SKIP_DOCKER); const shouldSkipPlaywrightInstall = truthy(process.env.PULSE_E2E_SKIP_PLAYWRIGHT_INSTALL); const DEFAULT_E2E_BOOTSTRAP_TOKEN = '0123456789abcdef0123456789abcdef0123456789abcdef'; if (!process.env.PULSE_E2E_BOOTSTRAP_TOKEN) { process.env.PULSE_E2E_BOOTSTRAP_TOKEN = DEFAULT_E2E_BOOTSTRAP_TOKEN; } const run = (command, args, options = {}) => new Promise((resolve, reject) => { const child = spawn(command, args, { stdio: 'inherit', ...options }); child.on('error', reject); child.on('close', (code) => { if (code === 0) resolve(); else reject(new Error(`${command} ${args.join(' ')} exited with code ${code}`)); }); }); const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx'; const canRun = async (command, args) => { try { await run(command, args, { stdio: 'ignore' }); return true; } catch { return false; } }; const waitForHealth = async (healthURL, timeoutMs = 120_000) => { const startedAt = Date.now(); while (Date.now() - startedAt < timeoutMs) { try { const res = await fetch(healthURL, { method: 'GET' }); if (res.ok) return; } catch { // ignore and retry } await new Promise((r) => setTimeout(r, 1000)); } throw new Error(`Timed out waiting for ${healthURL}`); }; if (truthy(process.env.PULSE_E2E_INSECURE_TLS)) { process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; } if (!shouldSkipPlaywrightInstall) { await run(npxCmd, ['playwright', 'install', 'chromium']); } if (shouldSkipDocker) { console.log('[integration] PULSE_E2E_SKIP_DOCKER enabled, skipping docker compose up'); process.exit(0); } const composeArgs = ['compose', '-f', 'docker-compose.test.yml', 'up', '-d']; const legacyComposeArgs = ['-f', 'docker-compose.test.yml', 'up', '-d']; const useDockerCompose = !(await canRun('docker', ['compose', 'version'])); console.log('[pretest] Starting docker compose...'); try { if (useDockerCompose) { console.log('[pretest] Using legacy docker-compose command'); await run('docker-compose', legacyComposeArgs); } else { console.log('[pretest] Using modern docker compose command'); await run('docker', composeArgs); } console.log('[pretest] Docker compose completed successfully'); } catch (error) { console.error('[pretest] Docker compose failed:', error.message); // Try to get container logs for debugging try { await run('docker', ['logs', 'pulse-test-server'], { stdio: 'inherit' }); } catch { // ignore } process.exit(1); } const baseURL = (process.env.PULSE_BASE_URL || 'http://localhost:7655').replace(/\/+$/, ''); console.log(`[pretest] Waiting for health check at ${baseURL}/api/health...`); try { await waitForHealth(`${baseURL}/api/health`); console.log('[pretest] Health check passed!'); } catch (error) { console.error('[pretest] Health check failed:', error.message); // Try to get container logs for debugging console.log('[pretest] Attempting to retrieve container logs...'); try { console.log('[pretest] === pulse-test-server logs ==='); await run('docker', ['logs', 'pulse-test-server'], { stdio: 'inherit' }); } catch { console.log('[pretest] Could not retrieve pulse-test-server logs'); } process.exit(1); }