/** * 本地 dev 服务健康预热:在 e2e 运行前 fail-fast, * 避免服务掉线时把 page.goto('/') / authedPage 失败误判为业务回归。 * * 边界: * - 仅检查可达性(Connection)+ 状态码 < 500;不校验业务响应 * - 不引入新依赖(Node 18+ 内置 fetch) * - 不自动启动/重启服务;仅指明修复路径 * - 不访问数据库 */ const WEB_URL = process.env.AIDOP_E2E_WEB_HEALTH_URL ?? 'http://localhost:8888/'; const API_URL = process.env.AIDOP_E2E_API_HEALTH_URL ?? 'http://localhost:5005/'; const TIMEOUT_MS = Number(process.env.AIDOP_E2E_HEALTH_TIMEOUT_MS ?? 5000); const RESTART_HINT = 'bash /home/yy968/work/New9S/restart_aidop.sh'; type ProbeOutcome = | { ok: true; status: number } | { ok: false; reason: string }; async function probe(name: string, url: string): Promise { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), TIMEOUT_MS); try { const resp = await fetch(url, { method: 'GET', redirect: 'manual', signal: controller.signal }); if (resp.status >= 500) { return { ok: false, reason: `${name} responded ${resp.status} (server-side error)` }; } return { ok: true, status: resp.status }; } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); return { ok: false, reason: `${name} unreachable (${msg})` }; } finally { clearTimeout(timer); } } export async function assertServicesHealthy(): Promise { const [web, api] = await Promise.all([ probe('Web', WEB_URL), probe('API', API_URL), ]); const failures: string[] = []; if (!web.ok) failures.push(` - Web ${WEB_URL} → ${web.reason}`); if (!api.ok) failures.push(` - API ${API_URL} → ${api.reason}`); if (failures.length > 0) { const msg = [ '[e2e health-check] dev services are not healthy:', ...failures, '', `Fix: ${RESTART_HINT}`, '(or override URLs via AIDOP_E2E_WEB_HEALTH_URL / AIDOP_E2E_API_HEALTH_URL)', ].join('\n'); throw new Error(msg); } // Concise success line so reviewers can confirm the gate ran. console.log(`[e2e health-check] OK Web=${web.status} API=${api.status}`); }