feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('Admin角色管理功能测试', () => {
|
||||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||||
testLogger.startTest('Admin角色管理功能测试');
|
||||
await page.goto(testConfig.getEnvironment().baseURL);
|
||||
|
||||
testLogger.startStep('前置步骤: 登录系统');
|
||||
|
||||
await page.fill('input[name="username"], input[placeholder*="用户名"]', 'admin');
|
||||
await page.fill('input[name="password"], input[placeholder*="密码"]', 'admin123');
|
||||
await page.click('button[type="submit"]');
|
||||
await page.waitForURL('**/dashboard');
|
||||
|
||||
testLogger.endStep('前置步骤: 登录系统', 'passed');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger }) => {
|
||||
testLogger.endTest('Admin角色管理功能测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-ROLE-001: 创建角色', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 导航到角色管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("角色管理")');
|
||||
await page.waitForURL('**/role-management');
|
||||
|
||||
testLogger.endStep('步骤1: 导航到角色管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 创建测试角色数据');
|
||||
|
||||
const testRole = await testDataManager.createTestRole({
|
||||
roleName: 'Admin测试角色001',
|
||||
roleCode: 'admin_test_role_001',
|
||||
description: 'Admin测试角色描述'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤2: 创建测试角色数据', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 点击新增按钮');
|
||||
|
||||
await page.click('button:has-text("新增")');
|
||||
await assertionHelper.assertModalVisible(page, '新增角色对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 点击新增按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 填写角色表单');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="roleName"]': { value: testRole.roleName },
|
||||
'input[name="roleCode"]': { value: testRole.roleCode },
|
||||
'textarea[name="description"]': { value: testRole.description || '' }
|
||||
});
|
||||
|
||||
await screenshotHelper.takeScreenshot('admin-role-form-filled');
|
||||
|
||||
testLogger.endStep('步骤4: 填写角色表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 选择权限');
|
||||
|
||||
const permissionCheckboxes = page.locator('.permission-checkbox, input[type="checkbox"][name*="permission"]');
|
||||
const checkboxCount = await permissionCheckboxes.count();
|
||||
|
||||
if (checkboxCount > 0) {
|
||||
await permissionCheckboxes.nth(0).check();
|
||||
await permissionCheckboxes.nth(1).check();
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤5: 选择权限', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 提交表单');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '角色创建成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 提交表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证角色已创建');
|
||||
|
||||
await tableHelper.waitForTableLoad('.role-table', 1);
|
||||
const matchingRows = await tableHelper.findRowsByCellText('.role-table', testRole.roleName);
|
||||
|
||||
expect(matchingRows.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤7: 验证角色已创建', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-create-role');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-ROLE-002: 编辑角色', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试角色');
|
||||
|
||||
const testRole = await testDataManager.createTestRole({
|
||||
roleName: 'Admin测试角色002',
|
||||
roleCode: 'admin_test_role_002',
|
||||
description: 'Admin测试角色描述'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到角色管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("角色管理")');
|
||||
await page.waitForURL('**/role-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到角色管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索角色');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testRole.roleName);
|
||||
await page.click('button:has-text("搜索")');
|
||||
await tableHelper.waitForTableLoad('.role-table', 1);
|
||||
|
||||
testLogger.endStep('步骤3: 搜索角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击编辑按钮');
|
||||
|
||||
await page.click('button:has-text("编辑")');
|
||||
await assertionHelper.assertModalVisible(page, '编辑角色对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击编辑按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 修改角色信息');
|
||||
|
||||
await formHelper.clearField('input[name="roleName"]');
|
||||
await formHelper.fillField('input[name="roleName"]', '修改后的角色名');
|
||||
|
||||
testLogger.endStep('步骤5: 修改角色信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 保存修改');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '角色更新成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 保存修改', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证修改已保存');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testRole.roleName);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowText = await tableHelper.getRowText('.role-table', 1);
|
||||
expect(rowText).toContain('修改后的角色名');
|
||||
|
||||
testLogger.endStep('步骤7: 验证修改已保存', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-edit-role');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-ROLE-003: 分配权限', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试角色');
|
||||
|
||||
const testRole = await testDataManager.createTestRole({
|
||||
roleName: 'Admin测试角色003',
|
||||
roleCode: 'admin_test_role_003',
|
||||
description: 'Admin测试角色描述'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到角色管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("角色管理")');
|
||||
await page.waitForURL('**/role-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到角色管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索角色');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testRole.roleName);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击权限分配按钮');
|
||||
|
||||
await page.click('button:has-text("权限分配")');
|
||||
await assertionHelper.assertModalVisible(page, '权限分配对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击权限分配按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 选择权限');
|
||||
|
||||
const permissionTree = page.locator('.permission-tree, .tree-container');
|
||||
await permissionTree.waitFor({ state: 'visible' });
|
||||
|
||||
const firstPermission = permissionTree.locator('.tree-node-checkbox, input[type="checkbox"]').first();
|
||||
await firstPermission.check();
|
||||
|
||||
testLogger.endStep('步骤5: 选择权限', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 保存权限分配');
|
||||
|
||||
await page.click('button:has-text("保存")');
|
||||
await assertionHelper.assertSuccessMessage(page, '权限分配成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 保存权限分配', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证权限已分配');
|
||||
|
||||
await page.click('button:has-text("权限分配")');
|
||||
await assertionHelper.assertModalVisible(page, '权限分配对话框应该显示');
|
||||
|
||||
const isChecked = await firstPermission.isChecked();
|
||||
expect(isChecked).toBe(true);
|
||||
|
||||
testLogger.endStep('步骤7: 验证权限已分配', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-assign-permissions');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-ROLE-004: 删除角色', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试角色');
|
||||
|
||||
const testRole = await testDataManager.createTestRole({
|
||||
roleName: 'Admin测试角色004',
|
||||
roleCode: 'admin_test_role_004',
|
||||
description: 'Admin测试角色描述'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到角色管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("角色管理")');
|
||||
await page.waitForURL('**/role-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到角色管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索角色');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testRole.roleName);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击删除按钮');
|
||||
|
||||
await page.click('button:has-text("删除")');
|
||||
await assertionHelper.assertModalVisible(page, '确认删除对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击删除按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 确认删除');
|
||||
|
||||
await page.click('button:has-text("确认")');
|
||||
await assertionHelper.assertSuccessMessage(page, '角色删除成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 确认删除', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证角色已删除');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testRole.roleName);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowCount = await tableHelper.getRowCount('.role-table');
|
||||
expect(rowCount).toBe(0);
|
||||
|
||||
testLogger.endStep('步骤6: 验证角色已删除', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-delete-role');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,317 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('Admin用户管理功能测试', () => {
|
||||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||||
testLogger.startTest('Admin用户管理功能测试');
|
||||
await page.goto(testConfig.getEnvironment().baseURL);
|
||||
|
||||
testLogger.startStep('前置步骤: 登录系统');
|
||||
|
||||
await page.fill('input[name="username"], input[placeholder*="用户名"]', 'admin');
|
||||
await page.fill('input[name="password"], input[placeholder*="密码"]', 'admin123');
|
||||
await page.click('button[type="submit"]');
|
||||
await page.waitForURL('**/dashboard');
|
||||
|
||||
testLogger.endStep('前置步骤: 登录系统', 'passed');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger }) => {
|
||||
testLogger.endTest('Admin用户管理功能测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-USER-001: 创建用户', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤1: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 创建测试用户数据');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'Admin测试用户001',
|
||||
email: 'admin_test_001@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤2: 创建测试用户数据', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 点击新增按钮');
|
||||
|
||||
await page.click('button:has-text("新增")');
|
||||
await assertionHelper.assertModalVisible(page, '新增用户对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 点击新增按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 填写用户表单');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="username"]': { value: testUser.username },
|
||||
'input[name="realName"]': { value: testUser.realName || '' },
|
||||
'input[name="email"]': { value: testUser.email || '' },
|
||||
'input[name="phone"]': { value: testUser.phone || '' }
|
||||
});
|
||||
|
||||
await screenshotHelper.takeScreenshot('admin-user-form-filled');
|
||||
|
||||
testLogger.endStep('步骤4: 填写用户表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 提交表单');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户创建成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 提交表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证用户已创建');
|
||||
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
const matchingRows = await tableHelper.findRowsByCellText('.user-table', testUser.username);
|
||||
|
||||
expect(matchingRows.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤6: 验证用户已创建', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-create-user');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-USER-002: 编辑用户', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'Admin测试用户002',
|
||||
email: 'admin_test_002@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
|
||||
testLogger.endStep('步骤3: 搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击编辑按钮');
|
||||
|
||||
await page.click('button:has-text("编辑")');
|
||||
await assertionHelper.assertModalVisible(page, '编辑用户对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击编辑按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 修改用户信息');
|
||||
|
||||
await formHelper.clearField('input[name="realName"]');
|
||||
await formHelper.fillField('input[name="realName"]', '修改后的用户名');
|
||||
|
||||
testLogger.endStep('步骤5: 修改用户信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 保存修改');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户更新成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 保存修改', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证修改已保存');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowText = await tableHelper.getRowText('.user-table', 1);
|
||||
expect(rowText).toContain('修改后的用户名');
|
||||
|
||||
testLogger.endStep('步骤7: 验证修改已保存', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-edit-user');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-USER-003: 删除用户', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'Admin测试用户003',
|
||||
email: 'admin_test_003@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击删除按钮');
|
||||
|
||||
await page.click('button:has-text("删除")');
|
||||
await assertionHelper.assertModalVisible(page, '确认删除对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击删除按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 确认删除');
|
||||
|
||||
await page.click('button:has-text("确认")');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户删除成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 确认删除', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证用户已删除');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowCount = await tableHelper.getRowCount('.user-table');
|
||||
expect(rowCount).toBe(0);
|
||||
|
||||
testLogger.endStep('步骤6: 验证用户已删除', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-delete-user');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-USER-004: 批量删除用户', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建多个测试用户');
|
||||
|
||||
const user1 = await testDataManager.createTestUser({
|
||||
realName: '批量删除用户1',
|
||||
email: 'batch_delete_1@example.com'
|
||||
});
|
||||
|
||||
const user2 = await testDataManager.createTestUser({
|
||||
realName: '批量删除用户2',
|
||||
email: 'batch_delete_2@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建多个测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder*="搜索"], .search-input', '批量删除用户');
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 选择所有用户');
|
||||
|
||||
await tableHelper.selectAllRows('.user-table');
|
||||
|
||||
testLogger.endStep('步骤4: 选择所有用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 点击批量删除按钮');
|
||||
|
||||
await page.click('button:has-text("批量删除")');
|
||||
await assertionHelper.assertModalVisible(page, '确认批量删除对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 点击批量删除按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 确认删除');
|
||||
|
||||
await page.click('button:has-text("确认")');
|
||||
await assertionHelper.assertSuccessMessage(page, '批量删除成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 确认删除', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证用户已删除');
|
||||
|
||||
const rowCount = await tableHelper.getRowCount('.user-table');
|
||||
expect(rowCount).toBe(0);
|
||||
|
||||
testLogger.endStep('步骤7: 验证用户已删除', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-batch-delete-user');
|
||||
});
|
||||
|
||||
test('TC-ADMIN-USER-005: 用户导出功能', async ({
|
||||
page,
|
||||
tableHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤1: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 等待表格加载');
|
||||
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
|
||||
testLogger.endStep('步骤2: 等待表格加载', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 点击导出按钮');
|
||||
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await page.click('button:has-text("导出")');
|
||||
|
||||
testLogger.endStep('步骤3: 点击导出按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证文件下载');
|
||||
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toMatch(/\.(xlsx|csv)$/);
|
||||
|
||||
testLogger.endStep('步骤4: 验证文件下载', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('admin-export-user');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,316 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('API集成测试', () => {
|
||||
test.beforeEach(async ({ apiHelper, testLogger }) => {
|
||||
testLogger.startTest('API集成测试');
|
||||
await apiHelper.login('admin', 'admin123');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ apiHelper, testLogger }) => {
|
||||
await apiHelper.logout();
|
||||
testLogger.endTest('API集成测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-API-001: 用户CRUD操作', async ({ apiHelper, assertionHelper, testLogger }) => {
|
||||
testLogger.startStep('步骤1: 创建用户');
|
||||
|
||||
const userData = {
|
||||
username: `api_test_${Date.now()}`,
|
||||
password: 'Test@123456',
|
||||
realName: 'API测试用户',
|
||||
email: `api_test_${Date.now()}@example.com`,
|
||||
phone: '13800138000',
|
||||
status: 1,
|
||||
gender: 1
|
||||
};
|
||||
|
||||
const createResponse = await apiHelper.post('/api/sys/user', userData);
|
||||
await assertionHelper.assertAPISuccess(createResponse, '创建用户API应该返回成功');
|
||||
|
||||
const createdUser = await createResponse.json();
|
||||
const userId = createdUser.data?.id || createdUser.id;
|
||||
|
||||
testLogger.endStep('步骤1: 创建用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 查询用户');
|
||||
|
||||
const getResponse = await apiHelper.get(`/api/sys/user/${userId}`);
|
||||
await assertionHelper.assertAPISuccess(getResponse, '查询用户API应该返回成功');
|
||||
|
||||
const getUser = await getResponse.json();
|
||||
expect(getUser.data?.username).toBe(userData.username);
|
||||
|
||||
testLogger.endStep('步骤2: 查询用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 更新用户');
|
||||
|
||||
const updateData = {
|
||||
id: userId,
|
||||
realName: '更新后的用户名',
|
||||
email: `updated_${Date.now()}@example.com`
|
||||
};
|
||||
|
||||
const updateResponse = await apiHelper.put('/api/sys/user', updateData);
|
||||
await assertionHelper.assertAPISuccess(updateResponse, '更新用户API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤3: 更新用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证更新');
|
||||
|
||||
const verifyResponse = await apiHelper.get(`/api/sys/user/${userId}`);
|
||||
const verifyUser = await verifyResponse.json();
|
||||
expect(verifyUser.data?.realName).toBe(updateData.realName);
|
||||
expect(verifyUser.data?.email).toBe(updateData.email);
|
||||
|
||||
testLogger.endStep('步骤4: 验证更新', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 删除用户');
|
||||
|
||||
const deleteResponse = await apiHelper.delete(`/api/sys/user/${userId}`);
|
||||
await assertionHelper.assertAPISuccess(deleteResponse, '删除用户API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤5: 删除用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证删除');
|
||||
|
||||
const verifyDeleteResponse = await apiHelper.get(`/api/sys/user/${userId}`);
|
||||
expect(verifyDeleteResponse.status()).toBe(404);
|
||||
|
||||
testLogger.endStep('步骤6: 验证删除', 'passed');
|
||||
});
|
||||
|
||||
test('TC-API-002: 角色CRUD操作', async ({ apiHelper, assertionHelper, testLogger }) => {
|
||||
testLogger.startStep('步骤1: 创建角色');
|
||||
|
||||
const roleData = {
|
||||
roleName: `API测试角色_${Date.now()}`,
|
||||
roleCode: `api_test_role_${Date.now()}`,
|
||||
description: 'API测试角色描述',
|
||||
status: 1
|
||||
};
|
||||
|
||||
const createResponse = await apiHelper.post('/api/sys/role', roleData);
|
||||
await assertionHelper.assertAPISuccess(createResponse, '创建角色API应该返回成功');
|
||||
|
||||
const createdRole = await createResponse.json();
|
||||
const roleId = createdRole.data?.id || createdRole.id;
|
||||
|
||||
testLogger.endStep('步骤1: 创建角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 查询角色列表');
|
||||
|
||||
const listResponse = await apiHelper.get('/api/sys/role/list');
|
||||
await assertionHelper.assertAPISuccess(listResponse, '查询角色列表API应该返回成功');
|
||||
|
||||
const roleList = await listResponse.json();
|
||||
expect(roleList.data?.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤2: 查询角色列表', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 查询单个角色');
|
||||
|
||||
const getResponse = await apiHelper.get(`/api/sys/role/${roleId}`);
|
||||
await assertionHelper.assertAPISuccess(getResponse, '查询角色API应该返回成功');
|
||||
|
||||
const getRole = await getResponse.json();
|
||||
expect(getRole.data?.roleName).toBe(roleData.roleName);
|
||||
|
||||
testLogger.endStep('步骤3: 查询单个角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 更新角色');
|
||||
|
||||
const updateData = {
|
||||
id: roleId,
|
||||
roleName: '更新后的角色名',
|
||||
description: '更新后的角色描述'
|
||||
};
|
||||
|
||||
const updateResponse = await apiHelper.put('/api/sys/role', updateData);
|
||||
await assertionHelper.assertAPISuccess(updateResponse, '更新角色API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤4: 更新角色', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 删除角色');
|
||||
|
||||
const deleteResponse = await apiHelper.delete(`/api/sys/role/${roleId}`);
|
||||
await assertionHelper.assertAPISuccess(deleteResponse, '删除角色API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤5: 删除角色', 'passed');
|
||||
});
|
||||
|
||||
test('TC-API-003: 菜单CRUD操作', async ({ apiHelper, assertionHelper, testLogger }) => {
|
||||
testLogger.startStep('步骤1: 创建菜单');
|
||||
|
||||
const menuData = {
|
||||
name: `API测试菜单_${Date.now()}`,
|
||||
code: `api_test_menu_${Date.now()}`,
|
||||
path: `/api-test-menu-${Date.now()}`,
|
||||
icon: 'SettingOutlined',
|
||||
sortOrder: 10,
|
||||
status: 1,
|
||||
parentId: 0
|
||||
};
|
||||
|
||||
const createResponse = await apiHelper.post('/api/sys/menu', menuData);
|
||||
await assertionHelper.assertAPISuccess(createResponse, '创建菜单API应该返回成功');
|
||||
|
||||
const createdMenu = await createResponse.json();
|
||||
const menuId = createdMenu.data?.id || createdMenu.id;
|
||||
|
||||
testLogger.endStep('步骤1: 创建菜单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 查询菜单树');
|
||||
|
||||
const treeResponse = await apiHelper.get('/api/sys/menu/tree');
|
||||
await assertionHelper.assertAPISuccess(treeResponse, '查询菜单树API应该返回成功');
|
||||
|
||||
const menuTree = await treeResponse.json();
|
||||
expect(menuTree.data?.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤2: 查询菜单树', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 查询单个菜单');
|
||||
|
||||
const getResponse = await apiHelper.get(`/api/sys/menu/${menuId}`);
|
||||
await assertionHelper.assertAPISuccess(getResponse, '查询菜单API应该返回成功');
|
||||
|
||||
const getMenu = await getResponse.json();
|
||||
expect(getMenu.data?.name).toBe(menuData.name);
|
||||
|
||||
testLogger.endStep('步骤3: 查询单个菜单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 更新菜单');
|
||||
|
||||
const updateData = {
|
||||
id: menuId,
|
||||
name: '更新后的菜单名',
|
||||
icon: 'EditOutlined'
|
||||
};
|
||||
|
||||
const updateResponse = await apiHelper.put('/api/sys/menu', updateData);
|
||||
await assertionHelper.assertAPISuccess(updateResponse, '更新菜单API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤4: 更新菜单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 删除菜单');
|
||||
|
||||
const deleteResponse = await apiHelper.delete(`/api/sys/menu/${menuId}`);
|
||||
await assertionHelper.assertAPISuccess(deleteResponse, '删除菜单API应该返回成功');
|
||||
|
||||
testLogger.endStep('步骤5: 删除菜单', 'passed');
|
||||
});
|
||||
|
||||
test('TC-API-004: 分页查询用户', async ({ apiHelper, assertionHelper, testLogger }) => {
|
||||
testLogger.startStep('步骤1: 创建多个测试用户');
|
||||
|
||||
const users = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const userData = {
|
||||
username: `pagination_test_${Date.now()}_${i}`,
|
||||
password: 'Test@123456',
|
||||
realName: `分页测试用户${i}`,
|
||||
email: `pagination_test_${i}@example.com`,
|
||||
phone: '13800138000',
|
||||
status: 1,
|
||||
gender: 1
|
||||
};
|
||||
|
||||
const createResponse = await apiHelper.post('/api/sys/user', userData);
|
||||
const createdUser = await createResponse.json();
|
||||
users.push(createdUser.data?.id || createdUser.id);
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤1: 创建多个测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 分页查询用户');
|
||||
|
||||
const page1Response = await apiHelper.get('/api/sys/user/page', {
|
||||
current: 1,
|
||||
size: 2
|
||||
});
|
||||
|
||||
await assertionHelper.assertAPISuccess(page1Response, '分页查询API应该返回成功');
|
||||
|
||||
const page1Data = await page1Response.json();
|
||||
expect(page1Data.data?.records?.length).toBeLessThanOrEqual(2);
|
||||
expect(page1Data.data?.total).toBeGreaterThanOrEqual(5);
|
||||
|
||||
testLogger.endStep('步骤2: 分页查询用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 查询第二页');
|
||||
|
||||
const page2Response = await apiHelper.get('/api/sys/user/page', {
|
||||
current: 2,
|
||||
size: 2
|
||||
});
|
||||
|
||||
await assertionHelper.assertAPISuccess(page2Response, '分页查询API应该返回成功');
|
||||
|
||||
const page2Data = await page2Response.json();
|
||||
expect(page2Data.data?.records?.length).toBeLessThanOrEqual(2);
|
||||
|
||||
testLogger.endStep('步骤3: 查询第二页', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 清理测试数据');
|
||||
|
||||
for (const userId of users) {
|
||||
await apiHelper.delete(`/api/sys/user/${userId}`);
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤4: 清理测试数据', 'passed');
|
||||
});
|
||||
|
||||
test('TC-API-005: 用户搜索功能', async ({ apiHelper, assertionHelper, testLogger }) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户');
|
||||
|
||||
const userData = {
|
||||
username: `search_test_${Date.now()}`,
|
||||
password: 'Test@123456',
|
||||
realName: '搜索测试用户',
|
||||
email: 'search_test@example.com',
|
||||
phone: '13800138000',
|
||||
status: 1,
|
||||
gender: 1
|
||||
};
|
||||
|
||||
const createResponse = await apiHelper.post('/api/sys/user', userData);
|
||||
const createdUser = await createResponse.json();
|
||||
const userId = createdUser.data?.id || createdUser.id;
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 按用户名搜索');
|
||||
|
||||
const searchResponse = await apiHelper.get('/api/sys/user/page', {
|
||||
username: userData.username
|
||||
});
|
||||
|
||||
await assertionHelper.assertAPISuccess(searchResponse, '搜索API应该返回成功');
|
||||
|
||||
const searchData = await searchResponse.json();
|
||||
expect(searchData.data?.records?.length).toBeGreaterThan(0);
|
||||
expect(searchData.data?.records?.[0]?.username).toBe(userData.username);
|
||||
|
||||
testLogger.endStep('步骤2: 按用户名搜索', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 按真实姓名搜索');
|
||||
|
||||
const searchByNameResponse = await apiHelper.get('/api/sys/user/page', {
|
||||
realName: userData.realName
|
||||
});
|
||||
|
||||
await assertionHelper.assertAPISuccess(searchByNameResponse, '按姓名搜索API应该返回成功');
|
||||
|
||||
const searchByNameData = await searchByNameResponse.json();
|
||||
expect(searchByNameData.data?.records?.length).toBeGreaterThan(0);
|
||||
expect(searchByNameData.data?.records?.[0]?.realName).toBe(userData.realName);
|
||||
|
||||
testLogger.endStep('步骤3: 按真实姓名搜索', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 清理测试数据');
|
||||
|
||||
await apiHelper.delete(`/api/sys/user/${userId}`);
|
||||
|
||||
testLogger.endStep('步骤4: 清理测试数据', 'passed');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
import { test, expect } from '../test-fixtures';
|
||||
|
||||
test.describe('AssertionHelper - 断言辅助工具使用示例', () => {
|
||||
test.beforeEach(async ({ testLogger }) => {
|
||||
testLogger.startTest('AssertionHelper测试');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger, helpers }) => {
|
||||
await helpers.screenshot.takeScreenshot('after-test');
|
||||
testLogger.endTest('AssertionHelper测试', 'passed');
|
||||
});
|
||||
|
||||
test('@smoke 元素可见性断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证登录表单可见');
|
||||
await helpers.assertion.assertElementVisible(page, 'input[name="username"]', '用户名输入框应该可见');
|
||||
await helpers.assertion.assertElementVisible(page, 'input[name="password"]', '密码输入框应该可见');
|
||||
await helpers.assertion.assertElementVisible(page, 'button[type="submit"]', '登录按钮应该可见');
|
||||
|
||||
testLogger.endStep('验证登录表单可见', 'passed');
|
||||
});
|
||||
|
||||
test('@smoke 元素文本断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证页面标题');
|
||||
await helpers.assertion.assertElementText(page, 'h1', '登录', '页面标题应该是"登录"');
|
||||
|
||||
testLogger.endStep('验证页面标题', 'passed');
|
||||
});
|
||||
|
||||
test('@smoke 元素状态断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证按钮状态');
|
||||
await helpers.assertion.assertElementEnabled(page, 'button[type="submit"]', '登录按钮应该启用');
|
||||
|
||||
testLogger.startStep('验证错误消息隐藏');
|
||||
await helpers.assertion.assertElementHidden(page, '.error-message', '错误消息应该隐藏');
|
||||
|
||||
testLogger.endStep('验证按钮状态', 'passed');
|
||||
});
|
||||
|
||||
test('@regression URL和标题断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证URL');
|
||||
await helpers.assertion.assertURL(page, /\/login/, 'URL应该包含/login');
|
||||
|
||||
testLogger.startStep('验证页面标题');
|
||||
await helpers.assertion.assertTitle(page, '登录 - 系统管理', '页面标题应该正确');
|
||||
|
||||
testLogger.endStep('验证URL和标题', 'passed');
|
||||
});
|
||||
|
||||
test('@regression 元素属性断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证输入框类型');
|
||||
await helpers.assertion.assertAttributeValue(page, 'input[name="password"]', 'type', 'password', '密码输入框应该是password类型');
|
||||
|
||||
testLogger.startStep('验证按钮类型');
|
||||
await helpers.assertion.assertAttributeValue(page, 'button[type="submit"]', 'type', 'submit', '登录按钮应该是submit类型');
|
||||
|
||||
testLogger.endStep('验证元素属性', 'passed');
|
||||
});
|
||||
|
||||
test('@regression 元素计数断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证输入框数量');
|
||||
await helpers.assertion.assertElementCount(page, 'input[type="text"]', 1, '应该有1个文本输入框');
|
||||
await helpers.assertion.assertElementCount(page, 'input[type="password"]', 1, '应该有1个密码输入框');
|
||||
|
||||
testLogger.endStep('验证元素计数', 'passed');
|
||||
});
|
||||
|
||||
test('@critical 表单验证断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证表单有效性');
|
||||
await helpers.assertion.assertFormValid(page, '登录表单应该有效');
|
||||
|
||||
testLogger.endStep('验证表单有效性', 'passed');
|
||||
});
|
||||
|
||||
test('@critical 成功和错误消息断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证错误消息隐藏');
|
||||
await helpers.assertion.assertErrorMessage(page, undefined, '错误消息应该隐藏');
|
||||
|
||||
testLogger.startStep('验证加载状态');
|
||||
await helpers.assertion.assertNotLoading(page, '页面不应该处于加载状态');
|
||||
|
||||
testLogger.endStep('验证消息状态', 'passed');
|
||||
});
|
||||
|
||||
test('@critical 模态框和Toast断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证模态框隐藏');
|
||||
await helpers.assertion.assertModalHidden(page, '模态框应该隐藏');
|
||||
|
||||
testLogger.startStep('验证Toast隐藏');
|
||||
await helpers.assertion.assertToastHidden(page, 'Toast消息应该隐藏');
|
||||
|
||||
testLogger.endStep('验证模态框和Toast', 'passed');
|
||||
});
|
||||
|
||||
test('@critical 表格数据断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到用户管理页面');
|
||||
await page.goto('/user-management');
|
||||
|
||||
testLogger.startStep('验证表格数据');
|
||||
const expectedData = [
|
||||
{ username: 'admin', realName: '管理员' },
|
||||
{ username: 'testuser', realName: '测试用户' }
|
||||
];
|
||||
|
||||
await helpers.assertion.assertTableData(page, '.ant-table', expectedData, '表格数据应该匹配');
|
||||
|
||||
testLogger.endStep('验证表格数据', 'passed');
|
||||
});
|
||||
|
||||
test('@critical CSS类断言', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证按钮CSS类');
|
||||
await helpers.assertion.assertCSSClass(page, 'button[type="submit"]', 'ant-btn', '登录按钮应该有ant-btn类');
|
||||
|
||||
testLogger.endStep('验证CSS类', 'passed');
|
||||
});
|
||||
|
||||
test('@critical 复合断言示例', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('导航到登录页面');
|
||||
await page.goto('/login');
|
||||
|
||||
testLogger.startStep('验证登录页面完整性');
|
||||
|
||||
await helpers.assertion.assertElementVisible(page, 'input[name="username"]', '用户名输入框应该可见');
|
||||
await helpers.assertion.assertElementVisible(page, 'input[name="password"]', '密码输入框应该可见');
|
||||
await helpers.assertion.assertElementVisible(page, 'button[type="submit"]', '登录按钮应该可见');
|
||||
await helpers.assertion.assertElementEnabled(page, 'button[type="submit"]', '登录按钮应该启用');
|
||||
await helpers.assertion.assertElementHidden(page, '.error-message', '错误消息应该隐藏');
|
||||
await helpers.assertion.assertURL(page, /\/login/, 'URL应该包含/login');
|
||||
await helpers.assertion.assertTitle(page, '登录 - 系统管理', '页面标题应该正确');
|
||||
|
||||
testLogger.endStep('验证登录页面完整性', 'passed');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,360 @@
|
||||
import { test, expect } from '../test-fixtures';
|
||||
|
||||
test.describe('登录功能测试', () => {
|
||||
test.beforeEach(async ({ testLogger }) => {
|
||||
testLogger.info('开始登录功能测试套件');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger, helpers }) => {
|
||||
testLogger.info('登录功能测试用例完成');
|
||||
await helpers.screenshot.takeScreenshot('after-test');
|
||||
});
|
||||
|
||||
test('成功登录', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('成功登录');
|
||||
|
||||
try {
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, testData.admin.password);
|
||||
|
||||
await pageObjects.dashboardPage.waitForLoad();
|
||||
|
||||
const pageTitle = await pageObjects.dashboardPage.getPageTitle();
|
||||
expect(pageTitle).toContain('仪表盘');
|
||||
|
||||
testLogger.endTest('成功登录', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('成功登录', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('登录失败 - 用户名错误', async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.startTest('登录失败 - 用户名错误');
|
||||
|
||||
try {
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login('wronguser', testData.admin.password);
|
||||
|
||||
const errorMessage = await pageObjects.loginPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('登录失败 - 用户名错误', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('登录失败 - 用户名错误', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('登录失败 - 密码错误', async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.startTest('登录失败 - 密码错误');
|
||||
|
||||
try {
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, 'wrongpassword');
|
||||
|
||||
const errorMessage = await pageObjects.loginPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('登录失败 - 密码错误', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('登录失败 - 密码错误', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('用户管理功能测试', () => {
|
||||
test.beforeEach(async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.info('开始用户管理功能测试套件');
|
||||
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, testData.admin.password);
|
||||
await pageObjects.dashboardPage.waitForLoad();
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger, helpers }) => {
|
||||
testLogger.info('用户管理功能测试用例完成');
|
||||
await helpers.screenshot.takeScreenshot('after-test');
|
||||
});
|
||||
|
||||
test('创建新用户', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('创建新用户');
|
||||
|
||||
try {
|
||||
await pageObjects.userManagementPage.navigate();
|
||||
await pageObjects.userManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.userManagementPage.clickAddUser();
|
||||
|
||||
await helpers.form.fillForm({
|
||||
username: testData.user.username,
|
||||
password: testData.user.password,
|
||||
email: testData.user.email,
|
||||
phone: testData.user.phone,
|
||||
realName: testData.user.realName,
|
||||
status: testData.user.status
|
||||
});
|
||||
|
||||
await helpers.form.submitForm();
|
||||
|
||||
const successMessage = await pageObjects.userManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('创建新用户', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('创建新用户', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('搜索用户', async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.startTest('搜索用户');
|
||||
|
||||
try {
|
||||
await pageObjects.userManagementPage.navigate();
|
||||
await pageObjects.userManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.userManagementPage.searchUser(testData.user.username);
|
||||
|
||||
const rowCount = await helpers.table.getRowCount('.ant-table');
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endTest('搜索用户', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('搜索用户', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('编辑用户', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('编辑用户');
|
||||
|
||||
try {
|
||||
await pageObjects.userManagementPage.navigate();
|
||||
await pageObjects.userManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.userManagementPage.searchUser(testData.user.username);
|
||||
|
||||
await pageObjects.userManagementPage.clickEditUser(0);
|
||||
|
||||
const updatedEmail = 'updated@example.com';
|
||||
await helpers.form.fillField('input[type="email"]', updatedEmail);
|
||||
|
||||
await helpers.form.submitForm();
|
||||
|
||||
const successMessage = await pageObjects.userManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('编辑用户', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('编辑用户', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('删除用户', async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.startTest('删除用户');
|
||||
|
||||
try {
|
||||
await pageObjects.userManagementPage.navigate();
|
||||
await pageObjects.userManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.userManagementPage.searchUser(testData.user.username);
|
||||
|
||||
await pageObjects.userManagementPage.clickDeleteUser(0);
|
||||
|
||||
await pageObjects.userManagementPage.confirmDelete();
|
||||
|
||||
const successMessage = await pageObjects.userManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('删除用户', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('删除用户', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('角色管理功能测试', () => {
|
||||
test.beforeEach(async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.info('开始角色管理功能测试套件');
|
||||
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, testData.admin.password);
|
||||
await pageObjects.dashboardPage.waitForLoad();
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger, helpers }) => {
|
||||
testLogger.info('角色管理功能测试用例完成');
|
||||
await helpers.screenshot.takeScreenshot('after-test');
|
||||
});
|
||||
|
||||
test('创建新角色', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('创建新角色');
|
||||
|
||||
try {
|
||||
await pageObjects.roleManagementPage.navigate();
|
||||
await pageObjects.roleManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.roleManagementPage.clickAddRole();
|
||||
|
||||
await helpers.form.fillForm({
|
||||
roleName: testData.role.roleName,
|
||||
roleCode: testData.role.roleCode,
|
||||
status: testData.role.status
|
||||
});
|
||||
|
||||
await helpers.form.submitForm();
|
||||
|
||||
const successMessage = await pageObjects.roleManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('创建新角色', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('创建新角色', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('分配权限给角色', async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.startTest('分配权限给角色');
|
||||
|
||||
try {
|
||||
await pageObjects.roleManagementPage.navigate();
|
||||
await pageObjects.roleManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.roleManagementPage.clickAssignPermissions(testData.role.roleCode);
|
||||
|
||||
await pageObjects.roleManagementPage.selectPermissions(['user:view', 'user:add']);
|
||||
|
||||
await pageObjects.roleManagementPage.savePermissions();
|
||||
|
||||
const successMessage = await pageObjects.roleManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('分配权限给角色', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('分配权限给角色', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('菜单管理功能测试', () => {
|
||||
test.beforeEach(async ({ pageObjects, testData, testLogger }) => {
|
||||
testLogger.info('开始菜单管理功能测试套件');
|
||||
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, testData.admin.password);
|
||||
await pageObjects.dashboardPage.waitForLoad();
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger, helpers }) => {
|
||||
testLogger.info('菜单管理功能测试用例完成');
|
||||
await helpers.screenshot.takeScreenshot('after-test');
|
||||
});
|
||||
|
||||
test('创建新菜单', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('创建新菜单');
|
||||
|
||||
try {
|
||||
await pageObjects.menuManagementPage.navigate();
|
||||
await pageObjects.menuManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.menuManagementPage.clickAddMenu();
|
||||
|
||||
await helpers.form.fillForm({
|
||||
menuName: testData.menu.menuName,
|
||||
menuType: testData.menu.menuType,
|
||||
path: testData.menu.path,
|
||||
status: testData.menu.status
|
||||
});
|
||||
|
||||
await helpers.form.submitForm();
|
||||
|
||||
const successMessage = await pageObjects.menuManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('创建新菜单', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('创建新菜单', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
test('菜单排序', async ({ pageObjects, testLogger }) => {
|
||||
testLogger.startTest('菜单排序');
|
||||
|
||||
try {
|
||||
await pageObjects.menuManagementPage.navigate();
|
||||
await pageObjects.menuManagementPage.waitForLoad();
|
||||
|
||||
await pageObjects.menuManagementPage.dragMenu(0, 1);
|
||||
|
||||
const successMessage = await pageObjects.menuManagementPage.getSuccessMessage();
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
testLogger.endTest('菜单排序', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('菜单排序', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('端到端测试', () => {
|
||||
test('完整的用户管理流程', async ({ pageObjects, testData, testLogger, helpers }) => {
|
||||
testLogger.startTest('完整的用户管理流程');
|
||||
|
||||
try {
|
||||
testLogger.startStep('用户登录');
|
||||
await pageObjects.loginPage.navigate();
|
||||
await pageObjects.loginPage.login(testData.admin.username, testData.admin.password);
|
||||
await pageObjects.dashboardPage.waitForLoad();
|
||||
testLogger.endStep('用户登录', 'passed');
|
||||
|
||||
testLogger.startStep('创建用户');
|
||||
await pageObjects.userManagementPage.navigate();
|
||||
await pageObjects.userManagementPage.waitForLoad();
|
||||
await pageObjects.userManagementPage.clickAddUser();
|
||||
|
||||
await helpers.form.fillForm({
|
||||
username: testData.user.username,
|
||||
password: testData.user.password,
|
||||
email: testData.user.email,
|
||||
phone: testData.user.phone,
|
||||
realName: testData.user.realName,
|
||||
status: testData.user.status
|
||||
});
|
||||
|
||||
await helpers.form.submitForm();
|
||||
testLogger.endStep('创建用户', 'passed');
|
||||
|
||||
testLogger.startStep('搜索用户');
|
||||
await pageObjects.userManagementPage.searchUser(testData.user.username);
|
||||
const rowCount = await helpers.table.getRowCount('.ant-table');
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
testLogger.endStep('搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('编辑用户');
|
||||
await pageObjects.userManagementPage.clickEditUser(0);
|
||||
const updatedEmail = 'updated@example.com';
|
||||
await helpers.form.fillField('input[type="email"]', updatedEmail);
|
||||
await helpers.form.submitForm();
|
||||
testLogger.endStep('编辑用户', 'passed');
|
||||
|
||||
testLogger.startStep('删除用户');
|
||||
await pageObjects.userManagementPage.searchUser(testData.user.username);
|
||||
await pageObjects.userManagementPage.clickDeleteUser(0);
|
||||
await pageObjects.userManagementPage.confirmDelete();
|
||||
testLogger.endStep('删除用户', 'passed');
|
||||
|
||||
testLogger.endTest('完整的用户管理流程', 'passed');
|
||||
} catch (error) {
|
||||
testLogger.endTest('完整的用户管理流程', 'failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,398 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { APIHelper } from '../helpers/api-helper';
|
||||
import { FormHelper } from '../helpers/form-helper';
|
||||
import { TableHelper } from '../helpers/table-helper';
|
||||
import { ScreenshotHelper } from '../helpers/screenshot-helper';
|
||||
|
||||
test.describe('测试辅助工具使用示例', () => {
|
||||
let apiHelper: APIHelper;
|
||||
let formHelper: FormHelper;
|
||||
let tableHelper: TableHelper;
|
||||
let screenshotHelper: ScreenshotHelper;
|
||||
|
||||
test.beforeEach(async ({ page, apiContext }) => {
|
||||
apiHelper = new APIHelper(apiContext, 'https://api.example.com');
|
||||
formHelper = new FormHelper(page, 'form#user-form');
|
||||
tableHelper = new TableHelper(page, 'table#data-table');
|
||||
screenshotHelper = new ScreenshotHelper(page);
|
||||
});
|
||||
|
||||
test('API辅助工具示例', async () => {
|
||||
test.info().annotations.push({ type: 'API测试', description: '演示API辅助工具的各种功能' });
|
||||
|
||||
await test.step('GET请求示例', async () => {
|
||||
const response = await apiHelper.get('/users');
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('POST请求示例', async () => {
|
||||
const userData = {
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
age: 30
|
||||
};
|
||||
|
||||
const response = await apiHelper.post('/users', userData);
|
||||
expect(response.success).toBe(true);
|
||||
expect(response.data).toMatchObject(userData);
|
||||
});
|
||||
|
||||
await test.step('带认证的请求示例', async () => {
|
||||
await apiHelper.login('/auth/login', {
|
||||
username: 'admin',
|
||||
password: 'password123'
|
||||
});
|
||||
|
||||
const response = await apiHelper.get('/protected/resource');
|
||||
expect(response.success).toBe(true);
|
||||
});
|
||||
|
||||
await test.step('文件上传示例', async () => {
|
||||
const response = await apiHelper.upload('/upload', '/path/to/file.pdf');
|
||||
expect(response.success).toBe(true);
|
||||
});
|
||||
|
||||
await test.step('错误处理示例', async () => {
|
||||
const response = await apiHelper.get('/nonexistent');
|
||||
expect(response.success).toBe(false);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
test('表单辅助工具示例', async ({ page }) => {
|
||||
test.info().annotations.push({ type: '表单测试', description: '演示表单辅助工具的各种功能' });
|
||||
|
||||
await page.goto('/user-form');
|
||||
|
||||
await test.step('配置表单字段', async () => {
|
||||
formHelper.setFields([
|
||||
{
|
||||
name: 'username',
|
||||
selector: 'input[name="username"]',
|
||||
type: 'text',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
selector: 'input[name="email"]',
|
||||
type: 'email',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'age',
|
||||
selector: 'input[name="age"]',
|
||||
type: 'number',
|
||||
required: false
|
||||
},
|
||||
{
|
||||
name: 'gender',
|
||||
selector: 'select[name="gender"]',
|
||||
type: 'select',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'agree',
|
||||
selector: 'input[name="agree"]',
|
||||
type: 'checkbox',
|
||||
required: true
|
||||
}
|
||||
]);
|
||||
|
||||
await formHelper.waitForFormReady();
|
||||
});
|
||||
|
||||
await test.step('填写表单', async () => {
|
||||
await formHelper.fillForm({
|
||||
username: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
age: '30',
|
||||
gender: '男',
|
||||
agree: true
|
||||
});
|
||||
|
||||
const formData = await formHelper.getFormData();
|
||||
expect(formData.username).toBe('张三');
|
||||
expect(formData.email).toBe('zhangsan@example.com');
|
||||
});
|
||||
|
||||
await test.step('验证表单', async () => {
|
||||
const validations = await formHelper.validate();
|
||||
const allValid = validations.every(v => v.valid);
|
||||
expect(allValid).toBe(true);
|
||||
});
|
||||
|
||||
await test.step('提交表单', async () => {
|
||||
await screenshotHelper.captureBeforeAction('form-submit');
|
||||
await formHelper.submit();
|
||||
await page.waitForTimeout(1000);
|
||||
await screenshotHelper.captureAfterAction('form-submit');
|
||||
});
|
||||
|
||||
await test.step('清空表单', async () => {
|
||||
await formHelper.clearForm();
|
||||
const formData = await formHelper.getFormData();
|
||||
expect(formData.username).toBe('');
|
||||
expect(formData.email).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
test('表格辅助工具示例', async ({ page }) => {
|
||||
test.info().annotations.push({ type: '表格测试', description: '演示表格辅助工具的各种功能' });
|
||||
|
||||
await page.goto('/data-table');
|
||||
|
||||
await test.step('配置表格列', async () => {
|
||||
tableHelper.setColumns([
|
||||
{
|
||||
name: 'id',
|
||||
selector: 'td:nth-child(1)',
|
||||
type: 'number',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
selector: 'td:nth-child(2)',
|
||||
type: 'text',
|
||||
sortable: true,
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
selector: 'td:nth-child(3)',
|
||||
type: 'text',
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
selector: 'td:nth-child(4)',
|
||||
type: 'text',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
selector: 'td:nth-child(5)',
|
||||
type: 'action'
|
||||
}
|
||||
]);
|
||||
|
||||
await tableHelper.waitForData();
|
||||
});
|
||||
|
||||
await test.step('获取表格数据', async () => {
|
||||
const rowCount = await tableHelper.getRowCount();
|
||||
expect(rowCount).toBeGreaterThan(0);
|
||||
|
||||
const rows = await tableHelper.getAllRows();
|
||||
expect(rows.length).toBe(rowCount);
|
||||
});
|
||||
|
||||
await test.step('查找行', async () => {
|
||||
const row = await tableHelper.findRowByColumn('name', '张三');
|
||||
expect(row).toBeDefined();
|
||||
expect(row?.data.name).toBe('张三');
|
||||
});
|
||||
|
||||
await test.step('过滤表格', async () => {
|
||||
await tableHelper.filterByColumn('name', '张三');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const filteredRows = await tableHelper.findRowsByColumn('name', '张三');
|
||||
expect(filteredRows.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
await test.step('排序表格', async () => {
|
||||
await tableHelper.sortByColumn('name', 'asc');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const sortOrder = await tableHelper.getSortOrder('name');
|
||||
expect(sortOrder).toBe('asc');
|
||||
});
|
||||
|
||||
await test.step('执行行操作', async () => {
|
||||
const row = await tableHelper.findRowByColumn('name', '张三');
|
||||
if (row) {
|
||||
await tableHelper.viewRow(row.index);
|
||||
await page.waitForTimeout(500);
|
||||
await page.goBack();
|
||||
}
|
||||
});
|
||||
|
||||
await test.step('选择行', async () => {
|
||||
await tableHelper.selectRow(0);
|
||||
const selectedRows = await tableHelper.getSelectedRows();
|
||||
expect(selectedRows.length).toBe(1);
|
||||
});
|
||||
|
||||
await test.step('分页操作', async () => {
|
||||
const totalPages = await tableHelper.getTotalPages();
|
||||
if (totalPages > 1) {
|
||||
await tableHelper.nextPage();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const currentPage = await tableHelper.getCurrentPage();
|
||||
expect(currentPage).toBe(2);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('截图辅助工具示例', async ({ page }) => {
|
||||
test.info().annotations.push({ type: '截图测试', description: '演示截图辅助工具的各种功能' });
|
||||
|
||||
await page.goto('/dashboard');
|
||||
|
||||
await test.step('捕获整页截图', async () => {
|
||||
const screenshotPath = await screenshotHelper.captureFullPage();
|
||||
expect(screenshotPath).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('捕获视口截图', async () => {
|
||||
const screenshotPath = await screenshotHelper.captureViewport();
|
||||
expect(screenshotPath).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('捕获元素截图', async () => {
|
||||
const element = page.locator('.dashboard-card');
|
||||
const screenshotPath = await screenshotHelper.captureElement(element);
|
||||
expect(screenshotPath).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('带描述的截图', async () => {
|
||||
const screenshotPath = await screenshotHelper.captureWithDescription('登录后的仪表盘');
|
||||
expect(screenshotPath).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('操作前后截图', async () => {
|
||||
await screenshotHelper.captureBeforeAction('button-click');
|
||||
|
||||
await page.click('.action-button');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await screenshotHelper.captureAfterAction('button-click');
|
||||
});
|
||||
|
||||
await test.step('步骤截图', async () => {
|
||||
await screenshotHelper.captureStep('步骤1: 打开菜单');
|
||||
await page.click('.menu-button');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await screenshotHelper.captureStep('步骤2: 选择选项');
|
||||
await page.click('.menu-item');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await screenshotHelper.captureStep('步骤3: 完成操作');
|
||||
});
|
||||
|
||||
await test.step('悬停截图', async () => {
|
||||
const element = page.locator('.hover-element');
|
||||
const screenshotPath = await screenshotHelper.captureOnHover(element);
|
||||
expect(screenshotPath).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('失败时截图', async () => {
|
||||
try {
|
||||
await page.click('.nonexistent-button');
|
||||
} catch (error) {
|
||||
const screenshotPath = await screenshotHelper.captureOnFailure('按钮点击失败', error as Error);
|
||||
expect(screenshotPath).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
await test.step('生成截图报告', async () => {
|
||||
const reportPath = await screenshotHelper.createScreenshotReport();
|
||||
expect(reportPath).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
test('综合测试示例', async ({ page, apiContext }) => {
|
||||
test.info().annotations.push({ type: '综合测试', description: '演示多个辅助工具的综合使用' });
|
||||
|
||||
await test.step('API登录', async () => {
|
||||
const loginResponse = await apiHelper.post('/auth/login', {
|
||||
username: 'testuser',
|
||||
password: 'testpass'
|
||||
});
|
||||
|
||||
expect(loginResponse.success).toBe(true);
|
||||
|
||||
const token = loginResponse.data.token;
|
||||
apiHelper.setToken(token);
|
||||
});
|
||||
|
||||
await test.step('导航到页面', async () => {
|
||||
await page.goto('/user-management');
|
||||
await screenshotHelper.captureStep('页面加载完成');
|
||||
});
|
||||
|
||||
await test.step('配置表单', async () => {
|
||||
formHelper.setFields([
|
||||
{
|
||||
name: 'username',
|
||||
selector: 'input[name="username"]',
|
||||
type: 'text',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
selector: 'input[name="email"]',
|
||||
type: 'email',
|
||||
required: true
|
||||
}
|
||||
]);
|
||||
|
||||
await formHelper.waitForFormReady();
|
||||
});
|
||||
|
||||
await test.step('填写并提交表单', async () => {
|
||||
await formHelper.fillForm({
|
||||
username: '新用户',
|
||||
email: 'newuser@example.com'
|
||||
});
|
||||
|
||||
await screenshotHelper.captureBeforeAction('表单提交');
|
||||
await formHelper.submit();
|
||||
await page.waitForTimeout(1000);
|
||||
await screenshotHelper.captureAfterAction('表单提交');
|
||||
});
|
||||
|
||||
await test.step('验证数据在表格中', async () => {
|
||||
tableHelper.setColumns([
|
||||
{
|
||||
name: 'username',
|
||||
selector: 'td:nth-child(2)',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
selector: 'td:nth-child(3)',
|
||||
type: 'text'
|
||||
}
|
||||
]);
|
||||
|
||||
await tableHelper.waitForData();
|
||||
|
||||
const row = await tableHelper.findRowByColumn('username', '新用户');
|
||||
expect(row).toBeDefined();
|
||||
expect(row?.data.email).toBe('newuser@example.com');
|
||||
});
|
||||
|
||||
await test.step('通过API验证数据', async () => {
|
||||
const response = await apiHelper.get('/users');
|
||||
expect(response.success).toBe(true);
|
||||
|
||||
const user = response.data.find((u: any) => u.username === '新用户');
|
||||
expect(user).toBeDefined();
|
||||
});
|
||||
|
||||
await test.step('清理数据', async () => {
|
||||
const row = await tableHelper.findRowByColumn('username', '新用户');
|
||||
if (row) {
|
||||
await tableHelper.deleteRow(row.index);
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
const deletedRow = await tableHelper.findRowByColumn('username', '新用户');
|
||||
expect(deletedRow).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,207 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { APIHelper } from '../helpers/api-helper';
|
||||
import { FormHelper } from '../helpers/form-helper';
|
||||
import { TableHelper } from '../helpers/table-helper';
|
||||
import { ScreenshotHelper } from '../helpers/screenshot-helper';
|
||||
|
||||
test.describe('测试辅助工具验证', () => {
|
||||
test('API辅助工具初始化验证', async ({ request }) => {
|
||||
const apiHelper = new APIHelper(request, 'https://api.example.com');
|
||||
|
||||
expect(apiHelper).toBeDefined();
|
||||
|
||||
apiHelper.setToken('test-token', 'Bearer');
|
||||
|
||||
expect(() => apiHelper.get('/test')).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('表单辅助工具初始化验证', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<form id="test-form">
|
||||
<input type="text" name="username" required>
|
||||
<input type="email" name="email" required>
|
||||
<input type="password" name="password" required>
|
||||
<select name="gender">
|
||||
<option value="male">男</option>
|
||||
<option value="female">女</option>
|
||||
</select>
|
||||
<input type="checkbox" name="agree" required>
|
||||
<button type="submit">提交</button>
|
||||
</form>
|
||||
`);
|
||||
|
||||
const formHelper = new FormHelper(page, 'form#test-form');
|
||||
|
||||
formHelper.setFields([
|
||||
{ name: 'username', selector: 'input[name="username"]', type: 'text', required: true },
|
||||
{ name: 'email', selector: 'input[name="email"]', type: 'email', required: true },
|
||||
{ name: 'password', selector: 'input[name="password"]', type: 'password', required: true },
|
||||
{ name: 'gender', selector: 'select[name="gender"]', type: 'select', required: true },
|
||||
{ name: 'agree', selector: 'input[name="agree"]', type: 'checkbox', required: true }
|
||||
]);
|
||||
|
||||
await formHelper.waitForFormReady();
|
||||
|
||||
await formHelper.fillForm({
|
||||
username: 'testuser',
|
||||
email: 'test@example.com',
|
||||
password: 'password123',
|
||||
gender: 'male',
|
||||
agree: true
|
||||
});
|
||||
|
||||
const formData = await formHelper.getFormData();
|
||||
expect(formData.username).toBe('testuser');
|
||||
expect(formData.email).toBe('test@example.com');
|
||||
});
|
||||
|
||||
test('表格辅助工具初始化验证', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<table id="test-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>张三</td>
|
||||
<td>zhangsan@example.com</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>李四</td>
|
||||
<td>lisi@example.com</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`);
|
||||
|
||||
const tableHelper = new TableHelper(page, 'table#test-table');
|
||||
|
||||
tableHelper.setColumns([
|
||||
{ name: 'id', selector: 'td:nth-child(1)', type: 'number' },
|
||||
{ name: 'name', selector: 'td:nth-child(2)', type: 'text' },
|
||||
{ name: 'email', selector: 'td:nth-child(3)', type: 'text' }
|
||||
]);
|
||||
|
||||
await tableHelper.waitForData();
|
||||
|
||||
const rowCount = await tableHelper.getRowCount();
|
||||
expect(rowCount).toBe(2);
|
||||
|
||||
const row = await tableHelper.findRowByColumn('name', '张三');
|
||||
expect(row).toBeDefined();
|
||||
expect(row?.data.name).toBe('张三');
|
||||
});
|
||||
|
||||
test('截图辅助工具初始化验证', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<html>
|
||||
<body>
|
||||
<h1>测试页面</h1>
|
||||
<p>这是一个测试页面</p>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const screenshotHelper = new ScreenshotHelper(page);
|
||||
|
||||
const screenshotPath = await screenshotHelper.captureViewport();
|
||||
|
||||
expect(screenshotPath).toBeDefined();
|
||||
expect(screenshotPath.endsWith('.png')).toBe(true);
|
||||
|
||||
const count = screenshotHelper.getScreenshotCount();
|
||||
expect(count).toBe(1);
|
||||
});
|
||||
|
||||
test('表单验证功能验证', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<form id="validation-form">
|
||||
<input type="text" name="username" required>
|
||||
<input type="email" name="email" required>
|
||||
<button type="submit">提交</button>
|
||||
</form>
|
||||
`);
|
||||
|
||||
const formHelper = new FormHelper(page, 'form#validation-form');
|
||||
|
||||
formHelper.setFields([
|
||||
{ name: 'username', selector: 'input[name="username"]', type: 'text', required: true },
|
||||
{ name: 'email', selector: 'input[name="email"]', type: 'email', required: true }
|
||||
]);
|
||||
|
||||
await formHelper.fillForm({
|
||||
username: 'testuser',
|
||||
email: 'invalid-email'
|
||||
});
|
||||
|
||||
const validations = await formHelper.validate();
|
||||
|
||||
const emailValidation = validations.find(v => v.field === 'email');
|
||||
expect(emailValidation?.valid).toBe(false);
|
||||
expect(emailValidation?.message).toBe('Invalid email format');
|
||||
});
|
||||
|
||||
test('表格查找功能验证', async ({ page }) => {
|
||||
await page.setContent(`
|
||||
<table id="search-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>用户1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>用户2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>用户1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`);
|
||||
|
||||
const tableHelper = new TableHelper(page, 'table#search-table');
|
||||
|
||||
tableHelper.setColumns([
|
||||
{ name: 'id', selector: 'td:nth-child(1)', type: 'number' },
|
||||
{ name: 'name', selector: 'td:nth-child(2)', type: 'text' }
|
||||
]);
|
||||
|
||||
await tableHelper.waitForData();
|
||||
|
||||
const rows = await tableHelper.findRowsByColumn('name', '用户1');
|
||||
expect(rows.length).toBe(2);
|
||||
});
|
||||
|
||||
test('截图管理功能验证', async ({ page }) => {
|
||||
await page.setContent('<html><body><h1>测试</h1></body></html>');
|
||||
|
||||
const screenshotHelper = new ScreenshotHelper(page);
|
||||
|
||||
await screenshotHelper.capture({ filename: 'test1' });
|
||||
await screenshotHelper.capture({ filename: 'test2' });
|
||||
await screenshotHelper.capture({ filename: 'test3' });
|
||||
|
||||
const count = screenshotHelper.getScreenshotCount();
|
||||
expect(count).toBe(3);
|
||||
|
||||
const screenshots = screenshotHelper.getAllScreenshots();
|
||||
expect(screenshots.length).toBe(3);
|
||||
|
||||
screenshotHelper.clearScreenshots();
|
||||
expect(screenshotHelper.getScreenshotCount()).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,292 @@
|
||||
import { test, expect } from '../test-fixtures';
|
||||
import { TestCoverageReporter } from '../core/test-coverage-reporter';
|
||||
|
||||
test.describe('TestCoverageReporter - 使用示例', () => {
|
||||
let coverageReporter: TestCoverageReporter;
|
||||
|
||||
test.beforeEach(() => {
|
||||
coverageReporter = new TestCoverageReporter();
|
||||
coverageReporter.startCoverage();
|
||||
});
|
||||
|
||||
test.afterEach(() => {
|
||||
coverageReporter.endCoverage();
|
||||
});
|
||||
|
||||
test('示例1: 基本使用 - 记录测试结果', async ({ page, testLogger }) => {
|
||||
testLogger.startStep('测试登录功能');
|
||||
|
||||
await page.goto('https://example.com/login');
|
||||
|
||||
const testResult = 'passed';
|
||||
const testDuration = 1500;
|
||||
const testTags = ['@smoke', '@critical'];
|
||||
const testFile = 'login.spec.ts';
|
||||
|
||||
coverageReporter.recordTestResult(
|
||||
'LoginTests',
|
||||
'登录功能测试',
|
||||
testResult,
|
||||
testDuration,
|
||||
testTags,
|
||||
testFile
|
||||
);
|
||||
|
||||
testLogger.endStep('测试登录功能', testResult);
|
||||
});
|
||||
|
||||
test('示例2: 批量记录测试结果', async ({ page, testLogger }) => {
|
||||
const testCases = [
|
||||
{ name: '用户名验证', status: 'passed' as const, duration: 800, tags: ['@smoke'] },
|
||||
{ name: '密码验证', status: 'passed' as const, duration: 900, tags: ['@smoke'] },
|
||||
{ name: '登录按钮点击', status: 'passed' as const, duration: 500, tags: ['@smoke'] },
|
||||
{ name: '登录成功跳转', status: 'failed' as const, duration: 2000, tags: ['@critical'] },
|
||||
{ name: '错误提示显示', status: 'passed' as const, duration: 600, tags: ['@normal'] }
|
||||
];
|
||||
|
||||
testLogger.startStep('批量记录测试结果');
|
||||
|
||||
testCases.forEach((testCase, index) => {
|
||||
coverageReporter.recordTestResult(
|
||||
'LoginTests',
|
||||
testCase.name,
|
||||
testCase.status,
|
||||
testCase.duration,
|
||||
testCase.tags,
|
||||
'login.spec.ts'
|
||||
);
|
||||
|
||||
testLogger.info(`测试用例 ${index + 1}: ${testCase.name} - ${testCase.status}`);
|
||||
});
|
||||
|
||||
testLogger.endStep('批量记录测试结果', 'completed');
|
||||
});
|
||||
|
||||
test('示例3: 多个测试套件', async ({ page, testLogger }) => {
|
||||
const suites = [
|
||||
{ name: 'LoginTests', tests: 3 },
|
||||
{ name: 'DashboardTests', tests: 5 },
|
||||
{ name: 'UserManagementTests', tests: 4 }
|
||||
];
|
||||
|
||||
testLogger.startStep('测试多个测试套件');
|
||||
|
||||
suites.forEach(suite => {
|
||||
for (let i = 1; i <= suite.tests; i++) {
|
||||
coverageReporter.recordTestResult(
|
||||
suite.name,
|
||||
`${suite.name} - 测试${i}`,
|
||||
'passed',
|
||||
1000,
|
||||
['@regression'],
|
||||
`${suite.name.toLowerCase()}.spec.ts`
|
||||
);
|
||||
}
|
||||
|
||||
testLogger.info(`${suite.name}: ${suite.tests}个测试用例`);
|
||||
});
|
||||
|
||||
testLogger.endStep('测试多个测试套件', 'completed');
|
||||
});
|
||||
|
||||
test('示例4: 生成覆盖率报告', async ({ page, testLogger }) => {
|
||||
testLogger.startStep('生成覆盖率报告');
|
||||
|
||||
coverageReporter.recordTestResult('ExampleTests', '测试1', 'passed', 1000, ['@smoke'], 'example.spec.ts');
|
||||
coverageReporter.recordTestResult('ExampleTests', '测试2', 'passed', 1000, ['@smoke'], 'example.spec.ts');
|
||||
coverageReporter.recordTestResult('ExampleTests', '测试3', 'failed', 2000, ['@critical'], 'example.spec.ts');
|
||||
coverageReporter.recordTestResult('ExampleTests', '测试4', 'skipped', 0, ['@normal'], 'example.spec.ts');
|
||||
|
||||
const coverage = coverageReporter.getCoverage();
|
||||
|
||||
testLogger.info(`总测试数: ${coverage.totalTests}`);
|
||||
testLogger.info(`通过测试: ${coverage.passedTests}`);
|
||||
testLogger.info(`失败测试: ${coverage.failedTests}`);
|
||||
testLogger.info(`跳过测试: ${coverage.skippedTests}`);
|
||||
testLogger.info(`通过率: ${coverage.passRate.toFixed(2)}%`);
|
||||
|
||||
testLogger.endStep('生成覆盖率报告', 'completed');
|
||||
});
|
||||
|
||||
test('示例5: 导出不同格式的报告', async ({ page, testLogger }) => {
|
||||
testLogger.startStep('导出不同格式的报告');
|
||||
|
||||
coverageReporter.recordTestResult('ExampleTests', '测试用例', 'passed', 1000, ['@smoke'], 'example.spec.ts');
|
||||
|
||||
const jsonReport = coverageReporter.exportCoverage('json');
|
||||
const htmlReport = coverageReporter.exportCoverage('html');
|
||||
const markdownReport = coverageReporter.exportCoverage('markdown');
|
||||
|
||||
testLogger.info('JSON报告长度:', jsonReport.length);
|
||||
testLogger.info('HTML报告长度:', htmlReport.length);
|
||||
testLogger.info('Markdown报告长度:', markdownReport.length);
|
||||
|
||||
testLogger.endStep('导出不同格式的报告', 'completed');
|
||||
});
|
||||
|
||||
test('示例6: 获取特定套件的覆盖率', async ({ page, testLogger }) => {
|
||||
testLogger.startStep('获取特定套件的覆盖率');
|
||||
|
||||
coverageReporter.recordTestResult('LoginTests', '测试1', 'passed', 1000, ['@smoke'], 'login.spec.ts');
|
||||
coverageReporter.recordTestResult('LoginTests', '测试2', 'passed', 1000, ['@smoke'], 'login.spec.ts');
|
||||
coverageReporter.recordTestResult('DashboardTests', '测试1', 'passed', 1000, ['@regression'], 'dashboard.spec.ts');
|
||||
|
||||
const loginSuite = coverageReporter.getSuiteCoverage('LoginTests');
|
||||
const dashboardSuite = coverageReporter.getSuiteCoverage('DashboardTests');
|
||||
|
||||
if (loginSuite) {
|
||||
testLogger.info(`LoginTests套件:`);
|
||||
testLogger.info(` 总测试数: ${loginSuite.totalTests}`);
|
||||
testLogger.info(` 通过测试: ${loginSuite.passedTests}`);
|
||||
testLogger.info(` 通过率: ${loginSuite.passRate.toFixed(2)}%`);
|
||||
}
|
||||
|
||||
if (dashboardSuite) {
|
||||
testLogger.info(`DashboardTests套件:`);
|
||||
testLogger.info(` 总测试数: ${dashboardSuite.totalTests}`);
|
||||
testLogger.info(` 通过测试: ${dashboardSuite.passedTests}`);
|
||||
testLogger.info(` 通过率: ${dashboardSuite.passRate.toFixed(2)}%`);
|
||||
}
|
||||
|
||||
testLogger.endStep('获取特定套件的覆盖率', 'completed');
|
||||
});
|
||||
|
||||
test('示例7: 与实际测试集成', async ({ page, helpers, testLogger }) => {
|
||||
testLogger.startStep('实际测试集成示例');
|
||||
|
||||
await page.goto('https://example.com');
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
await helpers.assertion.assertElementVisible(page, 'h1', '页面标题应该可见');
|
||||
coverageReporter.recordTestResult('PageTests', '页面标题可见性测试', 'passed', Date.now() - startTime, ['@smoke'], 'page.spec.ts');
|
||||
} catch (error) {
|
||||
coverageReporter.recordTestResult('PageTests', '页面标题可见性测试', 'failed', Date.now() - startTime, ['@smoke'], 'page.spec.ts');
|
||||
}
|
||||
|
||||
try {
|
||||
const title = await page.title();
|
||||
await helpers.assertion.assertTitle(page, /Example/, '页面标题应该包含Example');
|
||||
coverageReporter.recordTestResult('PageTests', '页面标题内容测试', 'passed', Date.now() - startTime, ['@smoke'], 'page.spec.ts');
|
||||
} catch (error) {
|
||||
coverageReporter.recordTestResult('PageTests', '页面标题内容测试', 'failed', Date.now() - startTime, ['@smoke'], 'page.spec.ts');
|
||||
}
|
||||
|
||||
testLogger.endStep('实际测试集成示例', 'completed');
|
||||
});
|
||||
|
||||
test('示例8: 完整的测试流程', async ({ page, helpers, testLogger }) => {
|
||||
const suiteName = 'CompleteTestFlow';
|
||||
const testFile = 'complete-flow.spec.ts';
|
||||
|
||||
testLogger.startStep('完整的测试流程');
|
||||
|
||||
const testSteps = [
|
||||
{ name: '打开登录页面', url: '/login', tags: ['@smoke'] },
|
||||
{ name: '输入用户名', tags: ['@smoke'] },
|
||||
{ name: '输入密码', tags: ['@smoke'] },
|
||||
{ name: '点击登录按钮', tags: ['@critical'] },
|
||||
{ name: '验证登录成功', tags: ['@critical'] }
|
||||
];
|
||||
|
||||
for (const step of testSteps) {
|
||||
const startTime = Date.now();
|
||||
testLogger.startStep(step.name);
|
||||
|
||||
try {
|
||||
if (step.url) {
|
||||
await page.goto(`https://example.com${step.url}`);
|
||||
}
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
coverageReporter.recordTestResult(
|
||||
suiteName,
|
||||
step.name,
|
||||
'passed',
|
||||
Date.now() - startTime,
|
||||
step.tags,
|
||||
testFile
|
||||
);
|
||||
|
||||
testLogger.endStep(step.name, 'passed');
|
||||
} catch (error) {
|
||||
coverageReporter.recordTestResult(
|
||||
suiteName,
|
||||
step.name,
|
||||
'failed',
|
||||
Date.now() - startTime,
|
||||
step.tags,
|
||||
testFile
|
||||
);
|
||||
|
||||
testLogger.endStep(step.name, 'failed');
|
||||
}
|
||||
}
|
||||
|
||||
testLogger.endStep('完整的测试流程', 'completed');
|
||||
});
|
||||
|
||||
test('示例9: 测试覆盖率阈值检查', async ({ page, testLogger }) => {
|
||||
const threshold = 80;
|
||||
|
||||
testLogger.startStep('测试覆盖率阈值检查');
|
||||
|
||||
coverageReporter.recordTestResult('ThresholdTests', '测试1', 'passed', 1000, ['@smoke'], 'threshold.spec.ts');
|
||||
coverageReporter.recordTestResult('ThresholdTests', '测试2', 'passed', 1000, ['@smoke'], 'threshold.spec.ts');
|
||||
coverageReporter.recordTestResult('ThresholdTests', '测试3', 'passed', 1000, ['@smoke'], 'threshold.spec.ts');
|
||||
coverageReporter.recordTestResult('ThresholdTests', '测试4', 'failed', 1000, ['@critical'], 'threshold.spec.ts');
|
||||
coverageReporter.recordTestResult('ThresholdTests', '测试5', 'passed', 1000, ['@smoke'], 'threshold.spec.ts');
|
||||
|
||||
const coverage = coverageReporter.getCoverage();
|
||||
|
||||
testLogger.info(`通过率: ${coverage.passRate.toFixed(2)}%`);
|
||||
testLogger.info(`阈值: ${threshold}%`);
|
||||
|
||||
if (coverage.passRate >= threshold) {
|
||||
testLogger.info('✅ 通过率满足阈值要求');
|
||||
} else {
|
||||
testLogger.error('❌ 通过率不满足阈值要求');
|
||||
}
|
||||
|
||||
testLogger.endStep('测试覆盖率阈值检查', 'completed');
|
||||
});
|
||||
|
||||
test('示例10: 测试结果统计', async ({ page, testLogger }) => {
|
||||
testLogger.startStep('测试结果统计');
|
||||
|
||||
const totalTests = 20;
|
||||
const passedTests = 15;
|
||||
const failedTests = 3;
|
||||
const skippedTests = 2;
|
||||
|
||||
for (let i = 1; i <= passedTests; i++) {
|
||||
coverageReporter.recordTestResult('StatsTests', `通过测试${i}`, 'passed', 1000, ['@smoke'], 'stats.spec.ts');
|
||||
}
|
||||
|
||||
for (let i = 1; i <= failedTests; i++) {
|
||||
coverageReporter.recordTestResult('StatsTests', `失败测试${i}`, 'failed', 1000, ['@critical'], 'stats.spec.ts');
|
||||
}
|
||||
|
||||
for (let i = 1; i <= skippedTests; i++) {
|
||||
coverageReporter.recordTestResult('StatsTests', `跳过测试${i}`, 'skipped', 0, ['@normal'], 'stats.spec.ts');
|
||||
}
|
||||
|
||||
const coverage = coverageReporter.getCoverage();
|
||||
|
||||
testLogger.info('测试结果统计:');
|
||||
testLogger.info(` 总测试数: ${coverage.totalTests} (期望: ${totalTests})`);
|
||||
testLogger.info(` 通过测试: ${coverage.passedTests} (期望: ${passedTests})`);
|
||||
testLogger.info(` 失败测试: ${coverage.failedTests} (期望: ${failedTests})`);
|
||||
testLogger.info(` 跳过测试: ${coverage.skippedTests} (期望: ${skippedTests})`);
|
||||
testLogger.info(` 通过率: ${coverage.passRate.toFixed(2)}%`);
|
||||
|
||||
expect(coverage.totalTests).toBe(totalTests);
|
||||
expect(coverage.passedTests).toBe(passedTests);
|
||||
expect(coverage.failedTests).toBe(failedTests);
|
||||
expect(coverage.skippedTests).toBe(skippedTests);
|
||||
|
||||
testLogger.endStep('测试结果统计', 'completed');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('Uniapp黄历功能测试', () => {
|
||||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||||
testLogger.startTest('Uniapp黄历功能测试');
|
||||
await page.goto(testConfig.getEnvironment().uniappBaseURL);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger }) => {
|
||||
testLogger.endTest('Uniapp黄历功能测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-ALMANAC-001: 黄历搜索功能', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 等待页面加载完成');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await assertionHelper.assertElementVisible(page, '.almanac-search-container', '黄历搜索容器应该显示');
|
||||
|
||||
testLogger.endStep('步骤1: 等待页面加载完成', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 输入搜索关键词');
|
||||
|
||||
const searchInput = page.locator('.search-input, input[placeholder*="搜索"]');
|
||||
await searchInput.fill('2024');
|
||||
|
||||
testLogger.endStep('步骤2: 输入搜索关键词', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 执行搜索');
|
||||
|
||||
const searchButton = page.locator('.search-button, button:has-text("搜索")');
|
||||
if (await searchButton.isVisible()) {
|
||||
await searchButton.click();
|
||||
} else {
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤3: 执行搜索', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 等待搜索结果加载');
|
||||
|
||||
await assertionHelper.assertLoading(page, '加载指示器应该显示');
|
||||
await assertionHelper.assertNotLoading(page, '加载指示器应该消失');
|
||||
|
||||
testLogger.endStep('步骤4: 等待搜索结果加载', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 验证搜索结果');
|
||||
|
||||
const searchResults = page.locator('.search-result-card, .almanac-item');
|
||||
const resultCount = await searchResults.count();
|
||||
|
||||
expect(resultCount).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤5: 验证搜索结果', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('almanac-search');
|
||||
});
|
||||
|
||||
test('TC-ALMANAC-002: 黄历详情查看', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 等待黄历列表加载');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await assertionHelper.assertElementVisible(page, '.almanac-list, .almanac-container', '黄历列表应该显示');
|
||||
|
||||
testLogger.endStep('步骤1: 等待黄历列表加载', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击第一个黄历项');
|
||||
|
||||
const firstAlmanacItem = page.locator('.almanac-item, .search-result-card').first();
|
||||
await firstAlmanacItem.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击第一个黄历项', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 验证详情页显示');
|
||||
|
||||
await page.waitForURL(/.*\/detail/);
|
||||
await assertionHelper.assertElementVisible(page, '.almanac-detail, .detail-container', '黄历详情应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 验证详情页显示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证详情信息完整性');
|
||||
|
||||
const detailElements = [
|
||||
'.almanac-date',
|
||||
'.almanac-gan-zhi',
|
||||
'.almanac-yi',
|
||||
'.almanac-ji',
|
||||
'.almanac-chong'
|
||||
];
|
||||
|
||||
for (const selector of detailElements) {
|
||||
const element = page.locator(selector);
|
||||
const isVisible = await element.isVisible().catch(() => false);
|
||||
if (isVisible) {
|
||||
const text = await element.textContent();
|
||||
expect(text?.trim()).toBeTruthy();
|
||||
}
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤4: 验证详情信息完整性', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 返回列表页');
|
||||
|
||||
const backButton = page.locator('.back-button, button:has-text("返回")');
|
||||
await backButton.click();
|
||||
|
||||
await assertionHelper.assertElementVisible(page, '.almanac-list, .almanac-container', '黄历列表应该重新显示');
|
||||
|
||||
testLogger.endStep('步骤5: 返回列表页', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('almanac-detail');
|
||||
});
|
||||
|
||||
test('TC-ALMANAC-003: 黄历收藏功能', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 等待黄历列表加载');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await assertionHelper.assertElementVisible(page, '.almanac-list, .almanac-container', '黄历列表应该显示');
|
||||
|
||||
testLogger.endStep('步骤1: 等待黄历列表加载', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击收藏按钮');
|
||||
|
||||
const favoriteButton = page.locator('.favorite-button, .collect-button').first();
|
||||
await favoriteButton.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击收藏按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 验证收藏成功提示');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '收藏成功提示应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 验证收藏成功提示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证收藏图标状态');
|
||||
|
||||
const isFavorited = await favoriteButton.getAttribute('class');
|
||||
expect(isFavorited).toContain('active', '收藏按钮应该处于激活状态');
|
||||
|
||||
testLogger.endStep('步骤4: 验证收藏图标状态', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 取消收藏');
|
||||
|
||||
await favoriteButton.click();
|
||||
await assertionHelper.assertToastVisible(page, '取消收藏提示应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 取消收藏', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('almanac-favorite');
|
||||
});
|
||||
|
||||
test('TC-ALMANAC-004: 黄历分享功能', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 进入黄历详情页');
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
const firstAlmanacItem = page.locator('.almanac-item, .search-result-card').first();
|
||||
await firstAlmanacItem.click();
|
||||
|
||||
testLogger.endStep('步骤1: 进入黄历详情页', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击分享按钮');
|
||||
|
||||
const shareButton = page.locator('.share-button, button:has-text("分享")');
|
||||
await shareButton.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击分享按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 验证分享弹窗显示');
|
||||
|
||||
await assertionHelper.assertModalVisible(page, '分享弹窗应该显示');
|
||||
await assertionHelper.assertElementVisible(page, '.share-options, .share-menu', '分享选项应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 验证分享弹窗显示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证分享渠道');
|
||||
|
||||
const shareChannels = ['微信', '朋友圈', '微博', '复制链接'];
|
||||
for (const channel of shareChannels) {
|
||||
const channelButton = page.locator(`.share-option:has-text("${channel}")`);
|
||||
const isVisible = await channelButton.isVisible().catch(() => false);
|
||||
if (isVisible) {
|
||||
expect(isVisible).toBe(true);
|
||||
}
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤4: 验证分享渠道', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 关闭分享弹窗');
|
||||
|
||||
const closeButton = page.locator('.modal-close, .close-button');
|
||||
await closeButton.click();
|
||||
|
||||
await assertionHelper.assertModalHidden(page, '分享弹窗应该关闭');
|
||||
|
||||
testLogger.endStep('步骤5: 关闭分享弹窗', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('almanac-share');
|
||||
});
|
||||
|
||||
test('TC-ALMANAC-005: 黄历历史记录', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 点击历史记录按钮');
|
||||
|
||||
const historyButton = page.locator('.history-button, button:has-text("历史")');
|
||||
if (await historyButton.isVisible()) {
|
||||
await historyButton.click();
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤1: 点击历史记录按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 验证历史记录列表显示');
|
||||
|
||||
const historyList = page.locator('.history-list, .history-container');
|
||||
if (await historyList.isVisible()) {
|
||||
await assertionHelper.assertElementVisible(page, '.history-list, .history-container', '历史记录列表应该显示');
|
||||
|
||||
const historyItems = page.locator('.history-item');
|
||||
const itemCount = await historyItems.count();
|
||||
|
||||
expect(itemCount).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤2: 验证历史记录列表显示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 清空历史记录');
|
||||
|
||||
const clearButton = page.locator('.clear-history, button:has-text("清空")');
|
||||
if (await clearButton.isVisible()) {
|
||||
await clearButton.click();
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '清空成功提示应该显示');
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤3: 清空历史记录', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('almanac-history');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,248 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('Uniapp用户功能测试', () => {
|
||||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||||
testLogger.startTest('Uniapp用户功能测试');
|
||||
await page.goto(testConfig.getEnvironment().uniappBaseURL);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger }) => {
|
||||
testLogger.endTest('Uniapp用户功能测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-USER-001: 用户登录功能', async ({
|
||||
page,
|
||||
formHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 点击登录按钮');
|
||||
|
||||
const loginButton = page.locator('.login-button, button:has-text("登录")');
|
||||
await loginButton.click();
|
||||
|
||||
testLogger.endStep('步骤1: 点击登录按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 验证登录表单显示');
|
||||
|
||||
await assertionHelper.assertModalVisible(page, '登录弹窗应该显示');
|
||||
await assertionHelper.assertElementVisible(page, '.login-form, .auth-form', '登录表单应该显示');
|
||||
|
||||
testLogger.endStep('步骤2: 验证登录表单显示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 填写登录信息');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="username"], input[placeholder*="用户名"]': { value: 'testuser' },
|
||||
'input[name="password"], input[placeholder*="密码"]': { value: 'password123' }
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤3: 填写登录信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 提交登录表单');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"], button:has-text("登录")');
|
||||
|
||||
testLogger.endStep('步骤4: 提交登录表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 验证登录成功');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '登录成功提示应该显示');
|
||||
await assertionHelper.assertElementVisible(page, '.user-avatar, .user-info', '用户信息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 验证登录成功', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-login');
|
||||
});
|
||||
|
||||
test('TC-USER-002: 用户注册功能', async ({
|
||||
page,
|
||||
formHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 点击注册按钮');
|
||||
|
||||
const registerButton = page.locator('.register-button, button:has-text("注册")');
|
||||
await registerButton.click();
|
||||
|
||||
testLogger.endStep('步骤1: 点击注册按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 验证注册表单显示');
|
||||
|
||||
await assertionHelper.assertModalVisible(page, '注册弹窗应该显示');
|
||||
await assertionHelper.assertElementVisible(page, '.register-form, .auth-form', '注册表单应该显示');
|
||||
|
||||
testLogger.endStep('步骤2: 验证注册表单显示', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 填写注册信息');
|
||||
|
||||
const timestamp = Date.now();
|
||||
await formHelper.fillForm({
|
||||
'input[name="username"], input[placeholder*="用户名"]': { value: `testuser_${timestamp}` },
|
||||
'input[name="password"], input[placeholder*="密码"]': { value: 'Password@123' },
|
||||
'input[name="confirmPassword"], input[placeholder*="确认密码"]': { value: 'Password@123' },
|
||||
'input[name="email"], input[placeholder*="邮箱"]': { value: `test_${timestamp}@example.com` },
|
||||
'input[name="phone"], input[placeholder*="手机号"]': { value: '13800138000' }
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤3: 填写注册信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 同意用户协议');
|
||||
|
||||
const agreeCheckbox = page.locator('input[type="checkbox"][name="agree"]');
|
||||
await agreeCheckbox.check();
|
||||
|
||||
testLogger.endStep('步骤4: 同意用户协议', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 提交注册表单');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"], button:has-text("注册")');
|
||||
|
||||
testLogger.endStep('步骤5: 提交注册表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证注册成功');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '注册成功提示应该显示');
|
||||
await assertionHelper.assertModalHidden(page, '注册弹窗应该关闭');
|
||||
|
||||
testLogger.endStep('步骤6: 验证注册成功', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-register');
|
||||
});
|
||||
|
||||
test('TC-USER-003: 用户信息修改', async ({
|
||||
page,
|
||||
formHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 进入个人中心');
|
||||
|
||||
const profileButton = page.locator('.profile-button, .user-avatar');
|
||||
await profileButton.click();
|
||||
|
||||
testLogger.endStep('步骤1: 进入个人中心', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击编辑资料按钮');
|
||||
|
||||
const editButton = page.locator('.edit-profile, button:has-text("编辑")');
|
||||
await editButton.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击编辑资料按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 修改用户信息');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="nickname"], input[placeholder*="昵称"]': { value: '新昵称' },
|
||||
'input[name="signature"], textarea[placeholder*="签名"]': { value: '这是我的个性签名' }
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤3: 修改用户信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 保存修改');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"], button:has-text("保存")');
|
||||
|
||||
testLogger.endStep('步骤4: 保存修改', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 验证修改成功');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '保存成功提示应该显示');
|
||||
|
||||
const nicknameElement = page.locator('.user-nickname');
|
||||
const nicknameText = await nicknameElement.textContent();
|
||||
expect(nicknameText).toContain('新昵称');
|
||||
|
||||
testLogger.endStep('步骤5: 验证修改成功', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-edit-profile');
|
||||
});
|
||||
|
||||
test('TC-USER-004: 用户退出登录', async ({
|
||||
page,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 进入个人中心');
|
||||
|
||||
const profileButton = page.locator('.profile-button, .user-avatar');
|
||||
await profileButton.click();
|
||||
|
||||
testLogger.endStep('步骤1: 进入个人中心', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击退出登录按钮');
|
||||
|
||||
const logoutButton = page.locator('.logout-button, button:has-text("退出")');
|
||||
await logoutButton.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击退出登录按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 确认退出');
|
||||
|
||||
const confirmButton = page.locator('.confirm-button, button:has-text("确认")');
|
||||
await confirmButton.click();
|
||||
|
||||
testLogger.endStep('步骤3: 确认退出', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 验证退出成功');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '退出成功提示应该显示');
|
||||
await assertionHelper.assertElementVisible(page, '.login-button, button:has-text("登录")', '登录按钮应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 验证退出成功', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-logout');
|
||||
});
|
||||
|
||||
test('TC-USER-005: 用户密码修改', async ({
|
||||
page,
|
||||
formHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 进入个人中心');
|
||||
|
||||
const profileButton = page.locator('.profile-button, .user-avatar');
|
||||
await profileButton.click();
|
||||
|
||||
testLogger.endStep('步骤1: 进入个人中心', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 点击修改密码按钮');
|
||||
|
||||
const changePasswordButton = page.locator('.change-password, button:has-text("修改密码")');
|
||||
await changePasswordButton.click();
|
||||
|
||||
testLogger.endStep('步骤2: 点击修改密码按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 填写密码修改表单');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="oldPassword"], input[placeholder*="旧密码"]': { value: 'password123' },
|
||||
'input[name="newPassword"], input[placeholder*="新密码"]': { value: 'NewPassword@123' },
|
||||
'input[name="confirmPassword"], input[placeholder*="确认密码"]': { value: 'NewPassword@123' }
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤3: 填写密码修改表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 提交修改');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"], button:has-text("确认")');
|
||||
|
||||
testLogger.endStep('步骤4: 提交修改', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 验证修改成功');
|
||||
|
||||
await assertionHelper.assertToastVisible(page, '密码修改成功提示应该显示');
|
||||
await assertionHelper.assertModalHidden(page, '修改密码弹窗应该关闭');
|
||||
|
||||
testLogger.endStep('步骤5: 验证修改成功', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-change-password');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,304 @@
|
||||
import { test, expect } from '../fixtures/test-fixtures';
|
||||
|
||||
test.describe('用户管理功能测试', () => {
|
||||
test.beforeEach(async ({ page, testConfig, testLogger }) => {
|
||||
testLogger.startTest('用户管理功能测试');
|
||||
await page.goto(testConfig.getEnvironment().baseURL);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ testLogger }) => {
|
||||
testLogger.endTest('用户管理功能测试', 'passed');
|
||||
});
|
||||
|
||||
test('TC-USER-001: 创建新用户流程', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
tableHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户数据');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'E2E测试用户001',
|
||||
email: 'e2e_test_001@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户数据', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 点击创建用户按钮');
|
||||
|
||||
await page.click('button:has-text("新增")');
|
||||
await assertionHelper.assertModalVisible(page, '新增用户对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤3: 点击创建用户按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 填写用户表单');
|
||||
|
||||
await formHelper.fillForm({
|
||||
'input[name="username"]': { value: testUser.username },
|
||||
'input[name="realName"]': { value: testUser.realName || '' },
|
||||
'input[name="email"]': { value: testUser.email || '' },
|
||||
'input[name="phone"]': { value: testUser.phone || '' }
|
||||
});
|
||||
|
||||
await screenshotHelper.takeScreenshot('user-form-filled');
|
||||
|
||||
testLogger.endStep('步骤4: 填写用户表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 提交表单');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户创建成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 提交表单', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证用户已创建');
|
||||
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
const matchingRows = await tableHelper.findRowsByCellText('.user-table', testUser.username);
|
||||
|
||||
expect(matchingRows.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤6: 验证用户已创建', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
|
||||
const rowText = await tableHelper.getRowText('.user-table', 1);
|
||||
expect(rowText).toContain(testUser.username);
|
||||
|
||||
testLogger.endStep('步骤7: 搜索用户', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('create-user');
|
||||
});
|
||||
|
||||
test('TC-USER-002: 编辑用户信息', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
formHelper,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'E2E测试用户002',
|
||||
email: 'e2e_test_002@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击编辑按钮');
|
||||
|
||||
await page.click('button:has-text("编辑")');
|
||||
await assertionHelper.assertModalVisible(page, '编辑用户对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击编辑按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 修改用户信息');
|
||||
|
||||
await formHelper.clearField('input[name="realName"]');
|
||||
await formHelper.fillField('input[name="realName"]', '修改后的用户名');
|
||||
|
||||
testLogger.endStep('步骤5: 修改用户信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 保存修改');
|
||||
|
||||
await formHelper.submitForm('button[type="submit"]');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户更新成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤6: 保存修改', 'passed');
|
||||
|
||||
testLogger.startStep('步骤7: 验证修改已保存');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowText = await page.locator('.user-table tbody tr').first().textContent();
|
||||
expect(rowText).toContain('修改后的用户名');
|
||||
|
||||
testLogger.endStep('步骤7: 验证修改已保存', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('edit-user');
|
||||
});
|
||||
|
||||
test('TC-USER-003: 删除用户', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
assertionHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建测试用户');
|
||||
|
||||
const testUser = await testDataManager.createTestUser({
|
||||
realName: 'E2E测试用户003',
|
||||
email: 'e2e_test_003@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 搜索用户');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
testLogger.endStep('步骤3: 搜索用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 点击删除按钮');
|
||||
|
||||
await page.click('button:has-text("删除")');
|
||||
await assertionHelper.assertModalVisible(page, '确认删除对话框应该显示');
|
||||
|
||||
testLogger.endStep('步骤4: 点击删除按钮', 'passed');
|
||||
|
||||
testLogger.startStep('步骤5: 确认删除');
|
||||
|
||||
await page.click('button:has-text("确认")');
|
||||
await assertionHelper.assertSuccessMessage(page, '用户删除成功消息应该显示');
|
||||
|
||||
testLogger.endStep('步骤5: 确认删除', 'passed');
|
||||
|
||||
testLogger.startStep('步骤6: 验证用户已删除');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', testUser.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const rowCount = await page.locator('.user-table tbody tr').count();
|
||||
expect(rowCount).toBe(0);
|
||||
|
||||
testLogger.endStep('步骤6: 验证用户已删除', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('delete-user');
|
||||
});
|
||||
|
||||
test('TC-USER-004: 用户列表分页功能', async ({
|
||||
page,
|
||||
tableHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤1: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 获取分页信息');
|
||||
|
||||
const paginationInfo = await tableHelper.getPaginationInfo('.user-table');
|
||||
|
||||
expect(paginationInfo.currentPage).toBe(1);
|
||||
expect(paginationInfo.totalRecords).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤2: 获取分页信息', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 切换到下一页');
|
||||
|
||||
if (paginationInfo.totalPages > 1) {
|
||||
await tableHelper.goToPage('.user-table', 2);
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
|
||||
const updatedPaginationInfo = await tableHelper.getPaginationInfo('.user-table');
|
||||
expect(updatedPaginationInfo.currentPage).toBe(2);
|
||||
} else {
|
||||
testLogger.info('只有一页数据,跳过分页测试');
|
||||
}
|
||||
|
||||
testLogger.endStep('步骤3: 切换到下一页', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-pagination');
|
||||
});
|
||||
|
||||
test('TC-USER-005: 用户搜索功能', async ({
|
||||
page,
|
||||
testDataManager,
|
||||
tableHelper,
|
||||
testLogger,
|
||||
screenshotHelper
|
||||
}) => {
|
||||
testLogger.startStep('步骤1: 创建多个测试用户');
|
||||
|
||||
const user1 = await testDataManager.createTestUser({
|
||||
realName: '搜索测试用户1',
|
||||
email: 'search_test_1@example.com'
|
||||
});
|
||||
|
||||
const user2 = await testDataManager.createTestUser({
|
||||
realName: '搜索测试用户2',
|
||||
email: 'search_test_2@example.com'
|
||||
});
|
||||
|
||||
testLogger.endStep('步骤1: 创建多个测试用户', 'passed');
|
||||
|
||||
testLogger.startStep('步骤2: 导航到用户管理页面');
|
||||
|
||||
await page.click('.menu-item:has-text("系统管理")');
|
||||
await page.click('.menu-item:has-text("用户管理")');
|
||||
await page.waitForURL('**/user-management');
|
||||
|
||||
testLogger.endStep('步骤2: 导航到用户管理页面', 'passed');
|
||||
|
||||
testLogger.startStep('步骤3: 按用户名搜索');
|
||||
|
||||
await page.fill('input[placeholder="搜索用户名"]', user1.username);
|
||||
await page.click('button:has-text("搜索")');
|
||||
|
||||
const matchingRows = await tableHelper.findRowsByCellText('.user-table', user1.username);
|
||||
expect(matchingRows.length).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤3: 按用户名搜索', 'passed');
|
||||
|
||||
testLogger.startStep('步骤4: 清空搜索条件');
|
||||
|
||||
await page.click('button:has-text("重置")');
|
||||
await tableHelper.waitForTableLoad('.user-table', 1);
|
||||
|
||||
const allRows = await tableHelper.getRowCount('.user-table');
|
||||
expect(allRows).toBeGreaterThan(0);
|
||||
|
||||
testLogger.endStep('步骤4: 清空搜索条件', 'passed');
|
||||
|
||||
await screenshotHelper.takeScreenshotOnSuccess('user-search');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user