#!/usr/bin/env node /** * 端到端测试启动器:先起 vite preview,再跑 Playwright,结束后确保关闭预览服务。 * 不使用 Playwright webServer,避免 vite preview 在部分环境下退出挂起。 * 用法:pnpm test:e2e(会先执行 build) */ import { spawn, spawnSync } from 'node:child_process'; import { setTimeout as delay } from 'node:timers/promises'; const baseUrl = 'http://127.0.0.1:4173'; const pnpm = process.env.npm_execpath ? [process.execPath, process.env.npm_execpath] : ['pnpm']; function runPnpm(args, options = {}) { return spawnSync(pnpm[0], [...pnpm.slice(1), ...args], { env: process.env, stdio: 'inherit', ...options, }); } const server = spawn(pnpm[0], [...pnpm.slice(1), '--filter', '@lingxi/web', 'preview'], { env: process.env, stdio: 'ignore', detached: true, }); async function waitForServer(url, timeoutMs = 60_000) { const startedAt = Date.now(); while (Date.now() - startedAt < timeoutMs) { try { const response = await fetch(url); if (response.ok) return; } catch { // 预览服务尚未就绪,继续重试。 } await delay(500); } throw new Error(`预览服务在 ${timeoutMs}ms 内未就绪:${url}`); } let exitCode = 1; try { await waitForServer(`${baseUrl}/login`); const result = runPnpm(['exec', 'playwright', 'test']); exitCode = result.status ?? 1; } finally { try { process.kill(-server.pid, 'SIGTERM'); } catch { // 进程可能已退出。 } await delay(1_000); try { process.kill(-server.pid, 'SIGKILL'); } catch { // 进程可能已退出。 } } process.exit(exitCode);