e2ad1331cc
feat(测试): 新增Playwright和Vitest测试配置 feat(测试): 添加测试覆盖率报告生成功能 feat(测试): 实现前后端测试脚本集成 fix(测试): 修复测试密码不匹配问题 fix(测试): 修正URL等待策略 fix(测试): 调整错误消息选择器 refactor(测试): 重构测试目录结构 refactor(测试): 优化测试用例组织方式 docs: 更新测试报告文档 docs: 添加测试覆盖率报告模板 ci: 添加Docker测试环境配置 ci: 实现测试自动化脚本 chore: 更新依赖版本 chore: 添加测试相关配置文件
387 lines
14 KiB
TypeScript
387 lines
14 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { LoginPage } from './pages/LoginPage';
|
|
import { DashboardPage } from './pages/DashboardPage';
|
|
import { RoleManagementPage } from './pages/RoleManagementPage';
|
|
import { TestDataManager } from './utils/testDataManager';
|
|
import { TestHelper } from './utils/testHelper';
|
|
|
|
test.describe('角色管理异常场景测试', () => {
|
|
let loginPage: LoginPage;
|
|
let dashboardPage: DashboardPage;
|
|
let roleManagementPage: RoleManagementPage;
|
|
let testRole: any;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
loginPage = new LoginPage(page);
|
|
dashboardPage = new DashboardPage(page);
|
|
roleManagementPage = new RoleManagementPage(page);
|
|
|
|
await loginPage.goto();
|
|
await loginPage.login('admin', 'admin123');
|
|
});
|
|
|
|
test.afterEach(async ({ page, request }) => {
|
|
await TestHelper.clearAllStorage(page);
|
|
|
|
if (testRole) {
|
|
await TestDataManager.deleteTestRole(request, testRole.roleKey);
|
|
testRole = null;
|
|
}
|
|
});
|
|
|
|
test('创建角色 - 重复角色键', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试创建重复角色键的角色', async () => {
|
|
await roleManagementPage.clickCreateRole();
|
|
await TestHelper.waitForElementVisible(page, '.el-dialog');
|
|
|
|
const roleData = {
|
|
roleName: '管理员',
|
|
roleKey: 'admin',
|
|
roleSort: '1',
|
|
status: '1',
|
|
remark: '重复角色键',
|
|
};
|
|
|
|
await roleManagementPage.fillRoleForm(roleData);
|
|
await roleManagementPage.submitForm();
|
|
});
|
|
|
|
await test.step('验证错误消息', async () => {
|
|
await TestHelper.waitForErrorMessage(page);
|
|
const errorMessage = await TestHelper.getElementText(page, '.el-message__content');
|
|
expect(errorMessage).toContain('角色键已存在');
|
|
});
|
|
});
|
|
|
|
test('创建角色 - 缺少必填字段', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试创建缺少必填字段的角色', async () => {
|
|
await roleManagementPage.clickCreateRole();
|
|
await TestHelper.waitForElementVisible(page, '.el-dialog');
|
|
|
|
const roleData = {
|
|
roleName: '',
|
|
roleKey: '',
|
|
roleSort: '',
|
|
status: '',
|
|
remark: '',
|
|
};
|
|
|
|
await roleManagementPage.fillRoleForm(roleData);
|
|
await roleManagementPage.submitForm();
|
|
});
|
|
|
|
await test.step('验证表单验证', async () => {
|
|
const submitButton = page.locator('.el-dialog__footer button[type="submit"]');
|
|
const isDisabled = await submitButton.evaluate(el => (el as HTMLButtonElement).disabled);
|
|
expect(isDisabled).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test('创建角色 - 无效角色键格式', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试创建无效角色键格式的角色', async () => {
|
|
await roleManagementPage.clickCreateRole();
|
|
await TestHelper.waitForElementVisible(page, '.el-dialog');
|
|
|
|
const roleData = {
|
|
roleName: `测试角色_${Date.now()}`,
|
|
roleKey: '无效角色键!@#',
|
|
roleSort: '1',
|
|
status: '1',
|
|
remark: '无效角色键格式',
|
|
};
|
|
|
|
await roleManagementPage.fillRoleForm(roleData);
|
|
await roleManagementPage.submitForm();
|
|
});
|
|
|
|
await test.step('验证角色键格式错误', async () => {
|
|
const roleKeyInput = page.locator('input[name="roleKey"]');
|
|
const hasError = await roleKeyInput.evaluate(el => el.classList.contains('is-error'));
|
|
expect(hasError).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test('编辑角色 - 不存在的角色ID', async ({ page }) => {
|
|
await test.step('尝试编辑不存在的角色', async () => {
|
|
await page.goto('/roles/999999/edit');
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('验证404错误或重定向', async () => {
|
|
const currentUrl = page.url();
|
|
expect(currentUrl).toMatch(/(404|roles)/);
|
|
});
|
|
});
|
|
|
|
test('删除角色 - 不存在的角色ID', async ({ page, request }) => {
|
|
await test.step('尝试删除不存在的角色', async () => {
|
|
const response = await request.delete('http://localhost:8084/api/roles/999999');
|
|
expect(response.status()).toBe(404);
|
|
});
|
|
});
|
|
|
|
test('删除角色 - 系统内置角色', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试删除系统内置角色', async () => {
|
|
const adminRoleRow = page.locator('table tbody tr').filter({ hasText: 'admin' }).first();
|
|
const deleteButton = adminRoleRow.locator('.delete-button');
|
|
|
|
if (await deleteButton.count() > 0) {
|
|
await deleteButton.click();
|
|
await TestHelper.waitForElementVisible(page, '.el-message-box');
|
|
|
|
await page.click('.el-message-box__btns .el-button--primary');
|
|
await TestHelper.waitForPageLoad(page);
|
|
}
|
|
});
|
|
|
|
await test.step('验证系统内置角色不能删除', async () => {
|
|
const adminRoleRow = page.locator('table tbody tr').filter({ hasText: 'admin' }).first();
|
|
await expect(adminRoleRow).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('搜索角色 - 空搜索条件', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('执行空搜索', async () => {
|
|
const searchInput = page.locator('input[placeholder*="搜索"]').or(page.locator('.search-input'));
|
|
if (await searchInput.count() > 0) {
|
|
await searchInput.fill('');
|
|
await TestHelper.waitForPageLoad(page);
|
|
}
|
|
});
|
|
|
|
await test.step('验证显示所有角色', async () => {
|
|
const roleCount = await page.locator('.el-table__body tr').count();
|
|
expect(roleCount).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
test('搜索角色 - 不存在的角色名', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('搜索不存在的角色', async () => {
|
|
const searchInput = page.locator('input[placeholder*="搜索"]').or(page.locator('.search-input'));
|
|
if (await searchInput.count() > 0) {
|
|
await searchInput.fill('nonexistentrole123456');
|
|
await TestHelper.waitForPageLoad(page);
|
|
}
|
|
});
|
|
|
|
await test.step('验证无结果', async () => {
|
|
const roleCount = await page.locator('.el-table__body tr').count();
|
|
expect(roleCount).toBe(0);
|
|
});
|
|
});
|
|
|
|
test('分配权限 - 角色不存在', async ({ page, request }) => {
|
|
await test.step('尝试为不存在的角色分配权限', async () => {
|
|
const response = await request.post('http://localhost:8084/api/roles/999999/permissions', {
|
|
data: { permissions: ['user:view'] }
|
|
});
|
|
expect(response.status()).toBe(404);
|
|
});
|
|
});
|
|
|
|
test('分配权限 - 无效权限标识', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试分配无效权限', async () => {
|
|
const firstRow = page.locator('.el-table__body tr').first();
|
|
await firstRow.click();
|
|
await TestHelper.waitForElementVisible(page, '.permission-dialog');
|
|
|
|
const invalidPermission = page.locator('.permission-item').filter({ hasText: 'invalid:permission' });
|
|
if (await invalidPermission.count() > 0) {
|
|
await invalidPermission.click();
|
|
await page.click('.permission-dialog .save-button');
|
|
await TestHelper.waitForPageLoad(page);
|
|
}
|
|
});
|
|
|
|
await test.step('验证权限分配失败', async () => {
|
|
await TestHelper.waitForErrorMessage(page);
|
|
});
|
|
});
|
|
|
|
test('角色状态切换 - 禁用后用户无法登录', async ({ page, request }) => {
|
|
testRole = TestDataManager.generateTestRole();
|
|
await TestDataManager.createTestRole(request, testRole);
|
|
|
|
const testUser = TestDataManager.generateTestUser({ roleIds: [testRole.id] });
|
|
await TestDataManager.createTestUser(request, testUser);
|
|
|
|
await test.step('禁用角色', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
|
|
const roleRow = page.locator('table tbody tr').filter({ hasText: testRole.roleName }).first();
|
|
await roleRow.locator('.status-toggle').click();
|
|
await TestHelper.waitForSuccessMessage(page);
|
|
});
|
|
|
|
await test.step('验证用户无法登录', async () => {
|
|
await loginPage.logout();
|
|
await loginPage.goto();
|
|
|
|
const testUser = TestDataManager.generateTestUser();
|
|
await loginPage.login(testUser.username, testUser.password);
|
|
|
|
await TestHelper.waitForErrorMessage(page);
|
|
const currentUrl = page.url();
|
|
expect(currentUrl).toContain('/login');
|
|
});
|
|
});
|
|
|
|
test('批量删除角色 - 未选择角色', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('尝试批量删除未选择的角色', async () => {
|
|
const batchDeleteButton = page.locator('button:has-text("批量删除")');
|
|
if (await batchDeleteButton.count() > 0) {
|
|
await batchDeleteButton.click();
|
|
}
|
|
});
|
|
|
|
await test.step('验证提示消息', async () => {
|
|
await TestHelper.waitForErrorMessage(page);
|
|
});
|
|
});
|
|
|
|
test('批量删除角色 - 包含系统内置角色', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('选择包含系统内置角色的多个角色', async () => {
|
|
const adminRoleRow = page.locator('table tbody tr').filter({ hasText: 'admin' }).first();
|
|
await adminRoleRow.locator('input[type="checkbox"]').check();
|
|
|
|
const otherRoleRow = page.locator('table tbody tr').nth(1);
|
|
if (await otherRoleRow.count() > 0) {
|
|
await otherRoleRow.locator('input[type="checkbox"]').check();
|
|
}
|
|
});
|
|
|
|
await test.step('尝试批量删除', async () => {
|
|
const batchDeleteButton = page.locator('button:has-text("批量删除")');
|
|
if (await batchDeleteButton.count() > 0) {
|
|
await batchDeleteButton.click();
|
|
await TestHelper.waitForElementVisible(page, '.el-message-box');
|
|
|
|
await page.click('.el-message-box__btns .el-button--primary');
|
|
await TestHelper.waitForPageLoad(page);
|
|
}
|
|
});
|
|
|
|
await test.step('验证系统内置角色未被删除', async () => {
|
|
const adminRoleRow = page.locator('table tbody tr').filter({ hasText: 'admin' }).first();
|
|
await expect(adminRoleRow).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('网络错误 - 创建角色时断网', async ({ page }) => {
|
|
await test.step('导航到角色管理页面', async () => {
|
|
await dashboardPage.navigateToRoleManagement();
|
|
await TestHelper.waitForPageLoad(page);
|
|
});
|
|
|
|
await test.step('模拟网络错误', async () => {
|
|
await page.route('**/api/roles', route => route.abort('failed'));
|
|
});
|
|
|
|
await test.step('尝试创建角色', async () => {
|
|
await roleManagementPage.clickCreateRole();
|
|
await TestHelper.waitForElementVisible(page, '.el-dialog');
|
|
|
|
const roleData = {
|
|
roleName: `测试角色_${Date.now()}`,
|
|
roleKey: `test_role_${Date.now()}`,
|
|
roleSort: '1',
|
|
status: '1',
|
|
remark: '测试角色',
|
|
};
|
|
|
|
await roleManagementPage.fillRoleForm(roleData);
|
|
await roleManagementPage.submitForm();
|
|
});
|
|
|
|
await test.step('验证网络错误提示', async () => {
|
|
await TestHelper.waitForErrorMessage(page);
|
|
});
|
|
});
|
|
|
|
test('并发操作 - 同时编辑同一角色', async ({ page, context }) => {
|
|
const page1 = page;
|
|
const page2 = await context.newPage();
|
|
|
|
await page1.goto('/roles');
|
|
await page2.goto('/roles');
|
|
|
|
await TestHelper.waitForPageLoad(page1);
|
|
await TestHelper.waitForPageLoad(page2);
|
|
|
|
const firstRow1 = page1.locator('.el-table__body tr').first();
|
|
const firstRow2 = page2.locator('.el-table__body tr').first();
|
|
|
|
await firstRow1.click();
|
|
await firstRow2.click();
|
|
|
|
await TestHelper.waitForElementVisible(page1, '.el-dialog');
|
|
await TestHelper.waitForElementVisible(page2, '.el-dialog');
|
|
|
|
await page1.fill('input[name="roleName"]', '并发编辑1');
|
|
await page2.fill('input[name="roleName"]', '并发编辑2');
|
|
|
|
await page1.click('.el-dialog__footer button[type="submit"]');
|
|
await TestHelper.waitForPageLoad(page1);
|
|
|
|
await page2.click('.el-dialog__footer button[type="submit"]');
|
|
await TestHelper.waitForPageLoad(page2);
|
|
|
|
await page1.goto('/roles');
|
|
await page2.goto('/roles');
|
|
|
|
await TestHelper.waitForPageLoad(page1);
|
|
await TestHelper.waitForPageLoad(page2);
|
|
|
|
const errorMessage1 = await TestHelper.getElementText(page1, '.el-message__content');
|
|
const errorMessage2 = await TestHelper.getElementText(page2, '.el-message__content');
|
|
|
|
expect(errorMessage1 || errorMessage2).toContain('数据已被其他用户修改');
|
|
});
|
|
});
|