From aedca1cf855eef23446d9181796dc4c401294e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 4 Apr 2026 13:29:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=A8=B3=E5=AE=9A=E6=80=A7=E5=92=8C=E5=8F=AF=E9=9D=A0=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加登录重试机制(最多3次),提高登录成功率 - 添加后端健康监控,每30秒检查一次后端状态 - 改进测试隔离,每个测试后清理localStorage和sessionStorage - 优化错误处理和日志输出 - 添加globalTeardown函数,确保测试后正确清理资源 --- novalon-manage-web/e2e/global-setup.ts | 71 ++++++++++++++++++ novalon-manage-web/e2e/pages/LoginPage.ts | 72 +++++++++++-------- .../e2e/system-integration-test.spec.ts | 8 +++ 3 files changed, 123 insertions(+), 28 deletions(-) diff --git a/novalon-manage-web/e2e/global-setup.ts b/novalon-manage-web/e2e/global-setup.ts index a8d53a4..1f5846a 100644 --- a/novalon-manage-web/e2e/global-setup.ts +++ b/novalon-manage-web/e2e/global-setup.ts @@ -8,6 +8,42 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let backendProcess: ChildProcess | null = null; +let healthCheckInterval: NodeJS.Timeout | null = null; + +async function checkBackendHealth(): Promise { + try { + const response = await fetch('http://localhost:8084/actuator/health', { + signal: AbortSignal.timeout(5000) + } as any); + if (response.ok) { + const data = await response.json(); + return data.status === 'UP'; + } + return false; + } catch (error) { + return false; + } +} + +function startHealthMonitoring() { + if (healthCheckInterval) { + clearInterval(healthCheckInterval); + } + + healthCheckInterval = setInterval(async () => { + const isHealthy = await checkBackendHealth(); + if (!isHealthy) { + console.error('⚠️ 后端服务健康检查失败!'); + } + }, 30000); +} + +function stopHealthMonitoring() { + if (healthCheckInterval) { + clearInterval(healthCheckInterval); + healthCheckInterval = null; + } +} async function globalSetup(config: FullConfig) { console.log('🚀 开始全局测试环境设置...'); @@ -84,6 +120,8 @@ async function globalSetup(config: FullConfig) { console.log('🧹 清理测试数据...'); await cleanupTestData(); + startHealthMonitoring(); + console.log('✅ 全局测试环境设置完成'); } @@ -198,4 +236,37 @@ async function cleanupTestData(): Promise { } } +async function globalTeardown() { + console.log('🧹 开始全局测试环境清理...'); + + stopHealthMonitoring(); + + if (backendProcess) { + console.log('🛑 停止后端服务...'); + backendProcess.kill('SIGTERM'); + + await new Promise((resolve) => { + if (backendProcess) { + backendProcess.on('exit', () => { + console.log('✅ 后端服务已停止'); + resolve(); + }); + + setTimeout(() => { + if (backendProcess) { + backendProcess.kill('SIGKILL'); + console.log('⚠️ 强制停止后端服务'); + resolve(); + } + }, 10000); + } else { + resolve(); + } + }); + } + + console.log('✅ 全局测试环境清理完成'); +} + export default globalSetup; +export { globalTeardown }; diff --git a/novalon-manage-web/e2e/pages/LoginPage.ts b/novalon-manage-web/e2e/pages/LoginPage.ts index 06d682c..dd1c863 100644 --- a/novalon-manage-web/e2e/pages/LoginPage.ts +++ b/novalon-manage-web/e2e/pages/LoginPage.ts @@ -22,38 +22,54 @@ export class LoginPage { await this.page.waitForLoadState('networkidle'); } - async login(username: string, password: string) { - console.log('Starting login process...'); - await this.usernameInput.fill(username); - await this.passwordInput.fill(password); - console.log('Filled username and password'); + async login(username: string, password: string, maxRetries: number = 3) { + let lastError: Error | null = null; - await this.loginButton.click(); - console.log('Clicked login button'); + for (let attempt = 1; attempt <= maxRetries; attempt++) { + console.log(`Login attempt ${attempt}/${maxRetries}`); + + try { + await this.usernameInput.fill(username); + await this.passwordInput.fill(password); + console.log('Filled username and password'); + + await this.loginButton.click(); + console.log('Clicked login button'); - try { - await this.page.waitForURL(/\/(dashboard|\/)$/, { timeout: 30000 }); - console.log('Successfully navigated to dashboard or home'); - await this.page.waitForLoadState('networkidle'); - console.log('Network idle achieved'); - await this.page.waitForTimeout(2000); - console.log('Wait completed'); - } catch (error) { - console.log('Login failed or timeout:', error); - const currentUrl = this.page.url(); - console.log('Current URL:', currentUrl); - - const errorMessage = await this.getErrorMessage(); - if (errorMessage) { - console.log('Login error message:', errorMessage); + await this.page.waitForURL(/\/(dashboard|\/)$/, { timeout: 30000 }); + console.log('Successfully navigated to dashboard or home'); + await this.page.waitForLoadState('networkidle'); + console.log('Network idle achieved'); + await this.page.waitForTimeout(2000); + console.log('Login completed successfully'); + return; + } catch (error) { + lastError = error as Error; + console.log(`Login attempt ${attempt} failed:`, error); + + const currentUrl = this.page.url(); + console.log('Current URL:', currentUrl); + + const errorMessage = await this.getErrorMessage(); + if (errorMessage) { + console.log('Login error message:', errorMessage); + } + + const token = await this.page.evaluate(() => localStorage.getItem('token')); + console.log('Token in localStorage:', token ? 'exists' : 'not found'); + + if (attempt < maxRetries) { + console.log(`Waiting 2 seconds before retry...`); + await this.page.waitForTimeout(2000); + + await this.goto(); + console.log('Navigated back to login page for retry'); + } } - - const token = await this.page.evaluate(() => localStorage.getItem('token')); - console.log('Token in localStorage:', token ? 'exists' : 'not found'); - - await this.page.waitForTimeout(1000); - throw error; } + + console.log(`All ${maxRetries} login attempts failed`); + throw lastError || new Error('Login failed after all retries'); } async getErrorMessage(): Promise { diff --git a/novalon-manage-web/e2e/system-integration-test.spec.ts b/novalon-manage-web/e2e/system-integration-test.spec.ts index dc9a3fa..9cc0446 100644 --- a/novalon-manage-web/e2e/system-integration-test.spec.ts +++ b/novalon-manage-web/e2e/system-integration-test.spec.ts @@ -33,6 +33,14 @@ test.describe('系统全面集成测试', () => { fileManagementPage = new FileManagementPage(page); }); + test.afterEach(async ({ page }) => { + // 清理localStorage,确保测试隔离 + await page.evaluate(() => { + localStorage.clear(); + sessionStorage.clear(); + }); + }); + test.describe('1. 用户认证流程测试', () => { test('1.1 正确的用户名和密码登录成功', async ({ page }) => { await loginPage.goto();