import { test, expect } from '@playwright/test'; import { LoginPage } from '../pages/login-page.js'; import { TestLogger } from '../core/test-logger.js'; /** * TDD: 用户认证模块测试 * * 测试策略: * 1. 正常流程测试 - 验证正确的登录流程 * 2. 边界条件测试 - 验证空值、格式错误等边界情况 * 3. 错误处理测试 - 验证错误凭证、服务器错误等情况 * * 目标覆盖率: 90%+ */ test.describe('TDD: 用户认证 - 正常流程', () => { let loginPage: LoginPage; let testLogger: TestLogger; test.beforeEach(async ({ page }) => { testLogger = new TestLogger(); loginPage = new LoginPage(page, testLogger); await loginPage.navigate(); }); test('应该成功登录并跳转到仪表盘 [正常流程]', async ({ page }) => { // Given: 用户在登录页面 await expect(loginPage.verifyOnLoginPage()).resolves.toBe(true); // When: 输入正确的用户名和密码 await loginPage.login('admin', 'admin123456'); // Then: 应该跳转到仪表盘 await loginPage.waitForLoginSuccess(); expect(page.url()).toContain('dashboard'); }); test('应该保持登录状态在页面刷新后 [正常流程]', async ({ page }) => { // Given: 用户已登录 await loginPage.login('admin', 'admin123456'); await loginPage.waitForLoginSuccess(); // When: 刷新页面 await page.reload(); await page.waitForLoadState('networkidle'); // Then: 应该仍在仪表盘页面 expect(page.url()).toContain('dashboard'); }); }); test.describe('TDD: 用户认证 - 边界条件', () => { let loginPage: LoginPage; let testLogger: TestLogger; test.beforeEach(async ({ page }) => { testLogger = new TestLogger(); loginPage = new LoginPage(page, testLogger); await loginPage.navigate(); }); test('应该拒绝空用户名 [边界条件]', async () => { // Given: 用户名为空 await loginPage.fillPassword('admin123456'); // When: 点击登录 await loginPage.clickLoginButton(); // Then: 应该显示验证错误 const isOnLoginPage = await loginPage.verifyOnLoginPage(); expect(isOnLoginPage).toBe(true); }); test('应该拒绝空密码 [边界条件]', async () => { // Given: 密码为空 await loginPage.fillUsername('admin'); // When: 点击登录 await loginPage.clickLoginButton(); // Then: 应该显示验证错误 const isOnLoginPage = await loginPage.verifyOnLoginPage(); expect(isOnLoginPage).toBe(true); }); test('应该拒绝超长用户名 [边界条件]', async () => { // Given: 超长用户名(超过50个字符) const longUsername = 'a'.repeat(51); await loginPage.fillUsername(longUsername); await loginPage.fillPassword('admin123456'); // When: 点击登录 await loginPage.clickLoginButton(); // Then: 应该显示错误 await expect(loginPage.waitForError()).resolves.toBeTruthy(); }); test('应该拒绝特殊字符用户名 [边界条件]', async () => { // Given: 包含特殊字符的用户名 await loginPage.fillUsername('admin'); await loginPage.fillPassword('admin123456'); // When: 点击登录 await loginPage.clickLoginButton(); // Then: 应该显示错误 await expect(loginPage.waitForError()).resolves.toBeTruthy(); }); }); test.describe('TDD: 用户认证 - 错误处理', () => { let loginPage: LoginPage; let testLogger: TestLogger; test.beforeEach(async ({ page }) => { testLogger = new TestLogger(); loginPage = new LoginPage(page, testLogger); await loginPage.navigate(); }); test('应该拒绝错误的用户名 [错误处理]', async () => { // Given: 错误的用户名 await loginPage.login('wronguser', 'admin123456'); // Then: 应该显示错误提示 const errorText = await loginPage.waitForError(); expect(errorText).toContain('用户名或密码错误'); // And: 仍在登录页面 expect(await loginPage.verifyOnLoginPage()).toBe(true); }); test('应该拒绝错误的密码 [错误处理]', async () => { // Given: 错误的密码 await loginPage.login('admin', 'wrongpassword'); // Then: 应该显示错误提示 const errorText = await loginPage.waitForError(); expect(errorText).toContain('用户名或密码错误'); // And: 仍在登录页面 expect(await loginPage.verifyOnLoginPage()).toBe(true); }); test('应该拒绝错误的用户名和密码组合 [错误处理]', async () => { // Given: 错误的用户名和密码 await loginPage.login('wronguser', 'wrongpassword'); // Then: 应该显示错误提示 const errorText = await loginPage.waitForError(); expect(errorText).toContain('用户名或密码错误'); }); test('应该处理多次登录失败 [错误处理]', async () => { // Given: 连续3次登录失败 for (let i = 0; i < 3; i++) { await loginPage.login('admin', 'wrongpassword'); await loginPage.waitForError(); await loginPage.clearForm(); } // When: 第4次使用正确密码 await loginPage.login('admin', 'admin123456'); // Then: 应该成功登录 await loginPage.waitForLoginSuccess(); expect(loginPage.verifyOnLoginPage()).resolves.toBe(false); }); }); test.describe('TDD: 用户认证 - 登出功能', () => { let loginPage: LoginPage; let testLogger: TestLogger; test.beforeEach(async ({ page }) => { testLogger = new TestLogger(); loginPage = new LoginPage(page, testLogger); // 先登录 await loginPage.navigate(); await loginPage.login('admin', 'admin123456'); await loginPage.waitForLoginSuccess(); }); test('应该成功登出并返回登录页面 [正常流程]', async ({ page }) => { // When: 点击用户菜单并选择退出 await page.click('.user-dropdown, .el-dropdown'); await page.waitForTimeout(500); await page.click('text=退出登录'); // Then: 应该返回登录页面 await page.waitForURL('**/login', { timeout: 10000 }); expect(page.url()).toContain('login'); // And: 登录表单应该可见 expect(await loginPage.verifyLoginFormExists()).toBe(true); }); test('应该清除登录状态在登出后 [正常流程]', async ({ page }) => { // Given: 用户已登出 await page.click('.user-dropdown, .el-dropdown'); await page.waitForTimeout(500); await page.click('text=退出登录'); await page.waitForURL('**/login', { timeout: 10000 }); // When: 直接访问仪表盘 await page.goto('http://localhost:5174/dashboard'); // Then: 应该被重定向到登录页面 await page.waitForTimeout(2000); expect(page.url()).toContain('login'); }); }); test.describe('TDD: 用户认证 - 权限验证', () => { let loginPage: LoginPage; let testLogger: TestLogger; test.beforeEach(async ({ page }) => { testLogger = new TestLogger(); loginPage = new LoginPage(page, testLogger); // 先登录 await loginPage.navigate(); await loginPage.login('admin', 'admin123456'); await loginPage.waitForLoginSuccess(); }); test('应该能够访问用户管理页面 [权限验证]', async ({ page }) => { // When: 访问用户管理页面 await page.goto('http://localhost:5174/sys/user'); await page.waitForLoadState('networkidle'); // Then: 应该成功加载页面 expect(page.url()).toContain('/sys/user'); // And: 页面应该包含用户管理相关内容 const pageContent = await page.textContent('body'); expect(pageContent).toMatch(/用户|管理/); }); test('应该能够访问角色管理页面 [权限验证]', async ({ page }) => { // When: 访问角色管理页面 await page.goto('http://localhost:5174/sys/role'); await page.waitForLoadState('networkidle'); // Then: 应该成功加载页面 expect(page.url()).toContain('/sys/role'); // And: 页面应该包含角色管理相关内容 const pageContent = await page.textContent('body'); expect(pageContent).toMatch(/角色|管理/); }); test('应该能够访问菜单管理页面 [权限验证]', async ({ page }) => { // When: 访问菜单管理页面 await page.goto('http://localhost:5174/sys/menu'); await page.waitForLoadState('networkidle'); // Then: 应该成功加载页面 expect(page.url()).toContain('/sys/menu'); // And: 页面应该包含菜单管理相关内容 const pageContent = await page.textContent('body'); expect(pageContent).toMatch(/菜单|管理/); }); });