From aaba9a8e64c41db4a21ce6f22543da3f05bbbbf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Tue, 7 Apr 2026 09:50:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(e2e):=20=E6=B7=BB=E5=8A=A0=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=9C=8D=E5=8A=A1=E5=90=AF=E5=8A=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - 测试访问 http://localhost:3002 但前端服务未启动 - 导致所有登录测试失败 修复: - 在 global-setup 中添加前端服务启动(pnpm run dev) - 添加 waitForFrontendReady 函数等待前端服务就绪 - 在 global-teardown 中添加前端服务停止逻辑 - 前端服务健康检查:http://localhost:3002 --- novalon-manage-web/e2e/global-setup.ts | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/novalon-manage-web/e2e/global-setup.ts b/novalon-manage-web/e2e/global-setup.ts index 1f5846a..47924cf 100644 --- a/novalon-manage-web/e2e/global-setup.ts +++ b/novalon-manage-web/e2e/global-setup.ts @@ -8,6 +8,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let backendProcess: ChildProcess | null = null; +let frontendProcess: ChildProcess | null = null; let healthCheckInterval: NodeJS.Timeout | null = null; async function checkBackendHealth(): Promise { @@ -117,6 +118,49 @@ async function globalSetup(config: FullConfig) { console.log('⏳ 等待后端服务就绪...'); await waitForBackendReady(); + const frontendDir = path.resolve(__dirname, '..'); + console.log('🌐 启动前端服务...'); + console.log(` 目录: ${frontendDir}`); + + frontendProcess = spawn('pnpm', ['run', 'dev'], { + cwd: frontendDir, + stdio: 'pipe', + shell: true, + detached: false, + env: { ...process.env, NODE_ENV: 'test' } + }); + + if (frontendProcess.stdout) { + frontendProcess.stdout.on('data', (data) => { + const output = data.toString(); + if (output.includes('Local:') || output.includes('localhost:3002')) { + console.log('✅ 前端服务启动成功'); + } + }); + } + + if (frontendProcess.stderr) { + frontendProcess.stderr.on('data', (data) => { + const output = data.toString(); + if (output.includes('ERROR') || output.includes('error')) { + console.error('❌ 前端服务启动错误:', output); + } + }); + } + + frontendProcess.on('error', (error) => { + console.error('❌ 前端服务启动失败:', error); + }); + + frontendProcess.on('exit', (code, signal) => { + if (code !== 0 && code !== null) { + console.error(`❌ 前端服务异常退出,退出码: ${code}, 信号: ${signal}`); + } + }); + + console.log('⏳ 等待前端服务就绪...'); + await waitForFrontendReady(); + console.log('🧹 清理测试数据...'); await cleanupTestData(); @@ -151,6 +195,31 @@ async function waitForBackendReady(): Promise { throw new Error('❌ 后端服务启动超时'); } +async function waitForFrontendReady(): Promise { + const maxRetries = 60; + const retryInterval = 1000; + + for (let i = 0; i < maxRetries; i++) { + try { + const response = await fetch('http://localhost:3002', { + signal: AbortSignal.timeout(5000) as any + }); + if (response.ok) { + console.log(`✅ 前端服务健康检查通过 (尝试 ${i + 1}/${maxRetries})`); + return; + } + } catch (error) { + // 服务还未就绪,继续等待 + } + + if (i < maxRetries - 1) { + await new Promise(resolve => setTimeout(resolve, retryInterval)); + } + } + + throw new Error('❌ 前端服务启动超时'); +} + async function cleanupTestData(): Promise { try { // 登录获取token @@ -265,6 +334,30 @@ async function globalTeardown() { }); } + if (frontendProcess) { + console.log('🛑 停止前端服务...'); + frontendProcess.kill('SIGTERM'); + + await new Promise((resolve) => { + if (frontendProcess) { + frontendProcess.on('exit', () => { + console.log('✅ 前端服务已停止'); + resolve(); + }); + + setTimeout(() => { + if (frontendProcess) { + frontendProcess.kill('SIGKILL'); + console.log('⚠️ 强制停止前端服务'); + resolve(); + } + }, 10000); + } else { + resolve(); + } + }); + } + console.log('✅ 全局测试环境清理完成'); }