08ea5fbe98
添加用户管理视图、API和状态管理文件
219 lines
6.8 KiB
TypeScript
219 lines
6.8 KiB
TypeScript
/**
|
|
* 认证模块端到端测试
|
|
* 测试登录、登出、Token刷新等认证流程
|
|
*/
|
|
|
|
import { test, expect, Page } from '@playwright/test';
|
|
import { TestLogger } from '../core/test-logger.js';
|
|
import { TestDataManager } from '../core/test-data-manager.js';
|
|
import { WorkflowExecutor } from '../core/workflow-executor.js';
|
|
import { TestReporter } from '../core/test-reporter.js';
|
|
import { LoginPage } from '../pages/login-page.js';
|
|
import { DashboardPage } from '../pages/dashboard-page.js';
|
|
|
|
test.describe('认证模块端到端测试', () => {
|
|
let page: Page;
|
|
let testLogger: TestLogger;
|
|
let testDataManager: TestDataManager;
|
|
let workflowExecutor: WorkflowExecutor;
|
|
let testReporter: TestReporter;
|
|
let loginPage: LoginPage;
|
|
let dashboardPage: DashboardPage;
|
|
|
|
test.beforeAll(async ({ browser }) => {
|
|
page = await browser.newPage();
|
|
testLogger = new TestLogger();
|
|
testDataManager = TestDataManager.getInstance(testLogger);
|
|
workflowExecutor = new WorkflowExecutor(testLogger);
|
|
testReporter = new TestReporter(testLogger);
|
|
|
|
loginPage = new LoginPage(page, testLogger);
|
|
dashboardPage = new DashboardPage(page);
|
|
|
|
testReporter.startSuite('认证模块端到端测试');
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
testReporter.endSuite();
|
|
testReporter.generateHTMLReport('认证模块E2E测试报告');
|
|
await page.close();
|
|
});
|
|
|
|
test.afterEach(async ({}, testInfo) => {
|
|
if (testInfo.status === 'failed') {
|
|
const screenshotPath = `test-results/screenshots/${testInfo.title}-${Date.now()}.png`;
|
|
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
testReporter.addScreenshot(screenshotPath);
|
|
}
|
|
});
|
|
|
|
test('应该成功登录并跳转到仪表盘', async () => {
|
|
testReporter.startTest('成功登录');
|
|
|
|
try {
|
|
await loginPage.navigate();
|
|
await loginPage.login('admin', 'admin123');
|
|
await loginPage.waitForLoginSuccess();
|
|
|
|
// 验证仪表盘页面
|
|
const pageTitle = await dashboardPage.getPageTitle();
|
|
expect(pageTitle).toContain('仪表盘');
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该拒绝错误的用户名', async () => {
|
|
testReporter.startTest('拒绝错误用户名');
|
|
|
|
try {
|
|
await loginPage.navigate();
|
|
await loginPage.login('wronguser', 'admin123');
|
|
|
|
const errorText = await loginPage.waitForError();
|
|
expect(errorText).toContain('错误');
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该拒绝错误的密码', async () => {
|
|
testReporter.startTest('拒绝错误密码');
|
|
|
|
try {
|
|
await loginPage.navigate();
|
|
await loginPage.login('admin', 'wrongpassword');
|
|
|
|
const errorText = await loginPage.waitForError();
|
|
expect(errorText).toContain('错误');
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该验证用户名不能为空', async () => {
|
|
testReporter.startTest('验证用户名不能为空');
|
|
|
|
try {
|
|
await loginPage.navigate();
|
|
await loginPage.clickLoginButton();
|
|
|
|
const hasError = await page.locator('[role="alert"]').isVisible();
|
|
expect(hasError).toBe(true);
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该成功登出', async () => {
|
|
testReporter.startTest('成功登出');
|
|
|
|
try {
|
|
// 先登录
|
|
await loginPage.navigate();
|
|
await loginPage.login('admin', 'admin123');
|
|
await loginPage.waitForLoginSuccess();
|
|
|
|
// 执行登出
|
|
await page.click('.ant-dropdown-link');
|
|
await page.waitForTimeout(500);
|
|
await page.click('.ant-dropdown-menu-item:has-text("退出")');
|
|
await page.waitForURL(/.*login/, { timeout: 10000 });
|
|
|
|
// 验证返回登录页面
|
|
const isLoginFormVisible = await loginPage.verifyLoginFormExists();
|
|
expect(isLoginFormVisible).toBe(true);
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该保持登录状态在页面刷新后', async () => {
|
|
testReporter.startTest('刷新后保持登录');
|
|
|
|
try {
|
|
// 先登录
|
|
await loginPage.navigate();
|
|
await loginPage.login('admin', 'admin123');
|
|
await loginPage.waitForLoginSuccess();
|
|
|
|
// 刷新页面
|
|
await page.reload();
|
|
await dashboardPage.waitForLoad();
|
|
|
|
// 验证仍在仪表盘
|
|
const isDashboardVisible = await dashboardPage.isDashboardVisible();
|
|
expect(isDashboardVisible).toBe(true);
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
test('应该完成完整的登录-操作-登出流程', async () => {
|
|
testReporter.startTest('完整认证流程');
|
|
|
|
try {
|
|
// 步骤1: 登录
|
|
testLogger.startStep('用户登录');
|
|
await loginPage.navigate();
|
|
await loginPage.login('admin', 'admin123');
|
|
await loginPage.waitForLoginSuccess();
|
|
testLogger.endStep('用户登录', 'passed');
|
|
|
|
// 步骤2: 访问仪表盘
|
|
testLogger.startStep('访问仪表盘');
|
|
await dashboardPage.waitForLoad();
|
|
const isDashboardVisible = await dashboardPage.isDashboardVisible();
|
|
expect(isDashboardVisible).toBe(true);
|
|
testLogger.endStep('访问仪表盘', 'passed');
|
|
|
|
// 步骤3: 访问用户管理
|
|
testLogger.startStep('访问用户管理');
|
|
await page.click('.ant-menu-item:has-text("用户管理")');
|
|
await page.waitForURL(/.*users/, { timeout: 10000 });
|
|
testLogger.endStep('访问用户管理', 'passed');
|
|
|
|
// 步骤4: 返回仪表盘
|
|
testLogger.startStep('返回仪表盘');
|
|
await page.click('.ant-menu-item:has-text("仪表盘")');
|
|
await page.waitForURL(/.*dashboard/, { timeout: 10000 });
|
|
testLogger.endStep('返回仪表盘', 'passed');
|
|
|
|
// 步骤5: 登出
|
|
testLogger.startStep('用户登出');
|
|
await page.click('.ant-dropdown-link');
|
|
await page.waitForTimeout(500);
|
|
await page.click('.ant-dropdown-menu-item:has-text("退出")');
|
|
await page.waitForURL(/.*login/, { timeout: 10000 });
|
|
testLogger.endStep('用户登出', 'passed');
|
|
|
|
// 验证返回登录页面
|
|
const isLoginFormVisible = await loginPage.verifyLoginFormExists();
|
|
expect(isLoginFormVisible).toBe(true);
|
|
|
|
testReporter.endTest('passed');
|
|
} catch (error) {
|
|
testReporter.endTest('failed', error as Error);
|
|
throw error;
|
|
}
|
|
});
|
|
});
|