Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
593 lines
19 KiB
TypeScript
593 lines
19 KiB
TypeScript
/**
|
|
* 权限控制功能端到端测试
|
|
* 测试权限管理、角色管理、权限验证等功能
|
|
*/
|
|
|
|
import { test, expect, Page } from '@playwright/test';
|
|
|
|
const TEST_CONFIG = {
|
|
baseURL: 'http://localhost:5173',
|
|
timeout: 30000,
|
|
superAdmin: {
|
|
username: 'super_admin',
|
|
password: 'super123456',
|
|
},
|
|
testUser: {
|
|
username: 'test_user',
|
|
password: 'test123456',
|
|
},
|
|
};
|
|
|
|
// 测试权限数据
|
|
const TEST_PERMISSION = {
|
|
name: '测试权限_' + Date.now(),
|
|
code: 'test:permission:' + Date.now(),
|
|
type: 'button',
|
|
parentId: null,
|
|
description: '这是一个测试权限',
|
|
resource: '/test/resource',
|
|
actions: ['view', 'create'],
|
|
};
|
|
|
|
// 测试角色数据
|
|
const TEST_ROLE = {
|
|
name: '测试角色_' + Date.now(),
|
|
code: 'test_role_' + Date.now(),
|
|
description: '这是一个测试角色',
|
|
status: 'active',
|
|
level: 2,
|
|
};
|
|
|
|
test.describe('权限管理功能测试', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
test.setTimeout(TEST_CONFIG.timeout);
|
|
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsSuperAdmin(page);
|
|
|
|
// 导航到权限管理页面
|
|
await page.click('[data-testid="menu-system"]');
|
|
await page.click('[data-testid="menu-permission-management"]');
|
|
await page.waitForURL(/\/system\/permission/);
|
|
});
|
|
|
|
test('应该正确显示权限管理页面', async ({ page }) => {
|
|
// 检查页面标题
|
|
await expect(page.locator('.page-title')).toContainText(
|
|
/权限管理|Permission Management/,
|
|
);
|
|
|
|
// 检查权限树结构
|
|
await expect(page.locator('.permission-tree')).toBeVisible();
|
|
await expect(page.locator('.ant-tree')).toBeVisible();
|
|
|
|
// 检查操作按钮
|
|
await expect(
|
|
page.locator('[data-testid="add-permission-button"]'),
|
|
).toBeVisible();
|
|
await expect(
|
|
page.locator('[data-testid="expand-all-button"]'),
|
|
).toBeVisible();
|
|
await expect(
|
|
page.locator('[data-testid="collapse-all-button"]'),
|
|
).toBeVisible();
|
|
|
|
// 检查权限详情面板
|
|
await expect(page.locator('.permission-details')).toBeVisible();
|
|
});
|
|
|
|
test('应该能创建新权限', async ({ page }) => {
|
|
// 点击添加权限按钮
|
|
await page.click('[data-testid="add-permission-button"]');
|
|
|
|
// 等待创建弹窗出现
|
|
await expect(page.locator('.ant-modal')).toBeVisible();
|
|
await expect(page.locator('.ant-modal-title')).toContainText(
|
|
/添加权限|新增权限/,
|
|
);
|
|
|
|
// 填写权限信息
|
|
await page.fill('[data-testid="form-name"]', TEST_PERMISSION.name);
|
|
await page.fill('[data-testid="form-code"]', TEST_PERMISSION.code);
|
|
await page.selectOption('[data-testid="form-type"]', TEST_PERMISSION.type);
|
|
await page.fill(
|
|
'[data-testid="form-description"]',
|
|
TEST_PERMISSION.description,
|
|
);
|
|
await page.fill('[data-testid="form-resource"]', TEST_PERMISSION.resource);
|
|
|
|
// 选择操作权限
|
|
for (const action of TEST_PERMISSION.actions) {
|
|
await page.check(`[data-testid="action-${action}"]`);
|
|
}
|
|
|
|
// 提交表单
|
|
await page.click('[data-testid="form-submit"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
await expect(page.locator('.ant-message-success')).toContainText(
|
|
/创建成功|添加成功/,
|
|
);
|
|
|
|
// 弹窗应该关闭
|
|
await expect(page.locator('.ant-modal')).not.toBeVisible();
|
|
|
|
// 在权限树中应该能找到新创建的权限
|
|
await expect(
|
|
page
|
|
.locator('.ant-tree-node-content-wrapper')
|
|
.filter({ hasText: TEST_PERMISSION.name }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test('权限树展开折叠功能应该正常工作', async ({ page }) => {
|
|
// 点击展开所有
|
|
await page.click('[data-testid="expand-all-button"]');
|
|
|
|
// 等待展开完成
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 检查是否有展开的节点
|
|
const expandedNodes = page.locator('.ant-tree-switcher-open');
|
|
expect(await expandedNodes.count()).toBeGreaterThan(0);
|
|
|
|
// 点击折叠所有
|
|
await page.click('[data-testid="collapse-all-button"]');
|
|
|
|
// 等待折叠完成
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 检查是否所有节点都被折叠
|
|
const collapsedNodes = page.locator('.ant-tree-switcher-close');
|
|
expect(await collapsedNodes.count()).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('权限详情查看应该正常工作', async ({ page }) => {
|
|
// 点击权限树中的一个节点
|
|
const firstPermissionNode = page
|
|
.locator('.ant-tree-node-content-wrapper')
|
|
.first();
|
|
await firstPermissionNode.click();
|
|
|
|
// 检查权限详情面板是否更新
|
|
await expect(page.locator('.permission-details')).toBeVisible();
|
|
await expect(page.locator('[data-testid="detail-name"]')).toBeVisible();
|
|
await expect(page.locator('[data-testid="detail-code"]')).toBeVisible();
|
|
await expect(page.locator('[data-testid="detail-type"]')).toBeVisible();
|
|
|
|
// 检查操作按钮
|
|
await expect(page.locator('[data-testid="edit-permission"]')).toBeVisible();
|
|
await expect(
|
|
page.locator('[data-testid="delete-permission"]'),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test('应该能编辑权限信息', async ({ page }) => {
|
|
// 点击刚创建的权限节点
|
|
const testPermissionNode = page
|
|
.locator('.ant-tree-node-content-wrapper')
|
|
.filter({ hasText: TEST_PERMISSION.name });
|
|
await testPermissionNode.click();
|
|
|
|
// 点击编辑按钮
|
|
await page.click('[data-testid="edit-permission"]');
|
|
|
|
// 等待编辑弹窗出现
|
|
await expect(page.locator('.ant-modal')).toBeVisible();
|
|
await expect(page.locator('.ant-modal-title')).toContainText(
|
|
/编辑权限|修改权限/,
|
|
);
|
|
|
|
// 修改描述
|
|
const newDescription = '已修改的测试权限描述';
|
|
await page.fill('[data-testid="form-description"]', newDescription);
|
|
|
|
// 提交修改
|
|
await page.click('[data-testid="form-submit"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
|
|
// 验证修改是否生效
|
|
await testPermissionNode.click();
|
|
await expect(
|
|
page.locator('[data-testid="detail-description"]'),
|
|
).toContainText(newDescription);
|
|
});
|
|
|
|
test('权限搜索功能应该正常工作', async ({ page }) => {
|
|
// 输入搜索关键词
|
|
await page.fill('[data-testid="permission-search"]', TEST_PERMISSION.name);
|
|
|
|
// 等待搜索结果
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 检查搜索结果
|
|
const visibleNodes = page.locator('.ant-tree-node-content-wrapper:visible');
|
|
const searchResults = visibleNodes.filter({
|
|
hasText: TEST_PERMISSION.name,
|
|
});
|
|
await expect(searchResults).toHaveCount({ min: 1 });
|
|
|
|
// 清空搜索
|
|
await page.fill('[data-testid="permission-search"]', '');
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 检查是否显示所有权限
|
|
expect(await visibleNodes.count()).toBeGreaterThan(1);
|
|
});
|
|
|
|
test('应该能删除权限', async ({ page }) => {
|
|
// 点击要删除的权限节点
|
|
const testPermissionNode = page
|
|
.locator('.ant-tree-node-content-wrapper')
|
|
.filter({ hasText: TEST_PERMISSION.name });
|
|
await testPermissionNode.click();
|
|
|
|
// 点击删除按钮
|
|
await page.click('[data-testid="delete-permission"]');
|
|
|
|
// 确认删除
|
|
await expect(page.locator('.ant-modal-confirm')).toBeVisible();
|
|
await page.click('.ant-btn-primary');
|
|
|
|
// 等待删除成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
|
|
// 验证权限已被删除
|
|
await expect(testPermissionNode).not.toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('角色管理功能测试', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsSuperAdmin(page);
|
|
|
|
// 导航到角色管理页面
|
|
await page.click('[data-testid="menu-system"]');
|
|
await page.click('[data-testid="menu-role-management"]');
|
|
await page.waitForURL(/\/system\/role/);
|
|
});
|
|
|
|
test('应该正确显示角色管理页面', async ({ page }) => {
|
|
// 检查页面标题
|
|
await expect(page.locator('.page-title')).toContainText(
|
|
/角色管理|Role Management/,
|
|
);
|
|
|
|
// 检查搜索表单
|
|
await expect(page.locator('[data-testid="search-name"]')).toBeVisible();
|
|
await expect(page.locator('[data-testid="search-status"]')).toBeVisible();
|
|
await expect(page.locator('[data-testid="search-button"]')).toBeVisible();
|
|
|
|
// 检查操作按钮
|
|
await expect(page.locator('[data-testid="add-role-button"]')).toBeVisible();
|
|
await expect(
|
|
page.locator('[data-testid="batch-delete-button"]'),
|
|
).toBeVisible();
|
|
|
|
// 检查角色列表表格
|
|
await expect(page.locator('.ant-table')).toBeVisible();
|
|
});
|
|
|
|
test('应该能创建新角色', async ({ page }) => {
|
|
// 点击添加角色按钮
|
|
await page.click('[data-testid="add-role-button"]');
|
|
|
|
// 等待创建弹窗出现
|
|
await expect(page.locator('.ant-modal')).toBeVisible();
|
|
await expect(page.locator('.ant-modal-title')).toContainText(
|
|
/添加角色|新增角色/,
|
|
);
|
|
|
|
// 填写角色信息
|
|
await page.fill('[data-testid="form-name"]', TEST_ROLE.name);
|
|
await page.fill('[data-testid="form-code"]', TEST_ROLE.code);
|
|
await page.fill('[data-testid="form-description"]', TEST_ROLE.description);
|
|
await page.selectOption('[data-testid="form-status"]', TEST_ROLE.status);
|
|
await page.fill('[data-testid="form-level"]', TEST_ROLE.level.toString());
|
|
|
|
// 提交表单
|
|
await page.click('[data-testid="form-submit"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
|
|
// 在列表中搜索新创建的角色
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
const roleRow = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_ROLE.name });
|
|
await expect(roleRow).toBeVisible();
|
|
});
|
|
|
|
test('角色权限分配应该正常工作', async ({ page }) => {
|
|
// 搜索刚创建的角色
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 点击权限分配按钮
|
|
const assignButton = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_ROLE.name })
|
|
.locator('[data-testid="assign-permissions"]');
|
|
await assignButton.click();
|
|
|
|
// 等待权限分配弹窗出现
|
|
await expect(page.locator('.ant-modal')).toBeVisible();
|
|
await expect(page.locator('.ant-modal-title')).toContainText(
|
|
/权限分配|分配权限/,
|
|
);
|
|
|
|
// 检查权限树
|
|
await expect(page.locator('.permission-tree')).toBeVisible();
|
|
|
|
// 选择一些权限
|
|
const permissionCheckboxes = page.locator('.ant-tree-checkbox');
|
|
await permissionCheckboxes.nth(0).click();
|
|
await permissionCheckboxes.nth(1).click();
|
|
|
|
// 保存权限分配
|
|
await page.click('[data-testid="save-permissions"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
});
|
|
|
|
test('角色状态切换应该正常工作', async ({ page }) => {
|
|
// 搜索角色
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
const roleRow = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_ROLE.name });
|
|
|
|
// 点击状态切换开关
|
|
const statusSwitch = roleRow.locator('[data-testid="status-switch"]');
|
|
await statusSwitch.click();
|
|
|
|
// 确认状态变更
|
|
await page.click('[data-testid="confirm-status-change"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
});
|
|
|
|
test('角色复制功能应该正常工作', async ({ page }) => {
|
|
// 搜索角色
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 点击复制按钮
|
|
const copyButton = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_ROLE.name })
|
|
.locator('[data-testid="copy-role"]');
|
|
await copyButton.click();
|
|
|
|
// 等待复制弹窗
|
|
await expect(page.locator('.ant-modal')).toBeVisible();
|
|
await expect(page.locator('.ant-modal-title')).toContainText(
|
|
/复制角色|克隆角色/,
|
|
);
|
|
|
|
// 修改角色名称和编码
|
|
const newName = '复制的测试角色_' + Date.now();
|
|
const newCode = 'copied_role_' + Date.now();
|
|
await page.fill('[data-testid="form-name"]', newName);
|
|
await page.fill('[data-testid="form-code"]', newCode);
|
|
|
|
// 确认复制
|
|
await page.click('[data-testid="form-submit"]');
|
|
|
|
// 等待成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
|
|
// 验证复制的角色出现在列表中
|
|
await page.fill('[data-testid="search-name"]', newName);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
await expect(
|
|
page.locator('.ant-table-tbody tr').filter({ hasText: newName }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test('应该能删除角色', async ({ page }) => {
|
|
// 搜索要删除的角色
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
// 点击删除按钮
|
|
const deleteButton = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_ROLE.name })
|
|
.locator('[data-testid="delete-button"]');
|
|
await deleteButton.click();
|
|
|
|
// 确认删除
|
|
await expect(page.locator('.ant-modal-confirm')).toBeVisible();
|
|
await page.click('.ant-btn-primary');
|
|
|
|
// 等待删除成功消息
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
|
|
// 验证角色已被删除
|
|
await page.reload();
|
|
await page.fill('[data-testid="search-name"]', TEST_ROLE.name);
|
|
await page.click('[data-testid="search-button"]');
|
|
await page.waitForTimeout(1000);
|
|
|
|
await expect(page.locator('.ant-empty')).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('权限验证功能测试', () => {
|
|
test('路由权限验证应该正常工作', async ({ page }) => {
|
|
// 使用普通用户登录
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsTestUser(page);
|
|
|
|
// 尝试访问系统管理页面(假设普通用户没有权限)
|
|
await page.goto(`${TEST_CONFIG.baseURL}/system/permission`);
|
|
|
|
// 应该显示403错误页面或被重定向
|
|
await expect(page.locator('.ant-result-403, .error-403')).toBeVisible();
|
|
|
|
// 或者检查是否被重定向到无权限页面
|
|
await expect(page.url()).toMatch(/\/403|\/unauthorized/);
|
|
});
|
|
|
|
test('菜单权限过滤应该正常工作', async ({ page }) => {
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsTestUser(page);
|
|
|
|
// 检查系统管理菜单是否被隐藏
|
|
await expect(page.locator('[data-testid="menu-system"]')).not.toBeVisible();
|
|
|
|
// 检查用户有权限的菜单是否显示
|
|
await expect(page.locator('[data-testid="menu-dashboard"]')).toBeVisible();
|
|
await expect(page.locator('[data-testid="menu-account"]')).toBeVisible();
|
|
});
|
|
|
|
test('按钮权限控制应该正常工作', async ({ page }) => {
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsTestUser(page);
|
|
|
|
// 访问账号列表页面
|
|
await page.goto(`${TEST_CONFIG.baseURL}/account/list`);
|
|
|
|
// 检查删除按钮是否被隐藏(假设普通用户没有删除权限)
|
|
await expect(
|
|
page.locator('[data-testid="delete-button"]'),
|
|
).not.toBeVisible();
|
|
|
|
// 但查看按钮应该可见
|
|
await expect(page.locator('[data-testid="view-button"]')).toBeVisible();
|
|
});
|
|
|
|
test('API权限验证应该正常工作', async ({ page }) => {
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsTestUser(page);
|
|
|
|
// 监听网络请求
|
|
page.on('response', async (response) => {
|
|
if (
|
|
response.url().includes('/api/system/permission') &&
|
|
response.request().method() === 'POST'
|
|
) {
|
|
// 检查是否返回403权限不足错误
|
|
expect(response.status()).toBe(403);
|
|
}
|
|
});
|
|
|
|
// 尝试通过开发者工具发送受限API请求
|
|
await page.evaluate(() => {
|
|
fetch('/api/system/permission', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: `Bearer ${localStorage.getItem('access_token')}`,
|
|
},
|
|
body: JSON.stringify({ name: 'test', code: 'test' }),
|
|
});
|
|
});
|
|
|
|
// 等待请求完成
|
|
await page.waitForTimeout(2000);
|
|
});
|
|
|
|
test('权限缓存和实时更新应该正常工作', async ({ page }) => {
|
|
// 使用超级管理员登录
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsSuperAdmin(page);
|
|
|
|
// 创建一个测试用户并分配有限权限
|
|
await page.click('[data-testid="menu-system"]');
|
|
await page.click('[data-testid="menu-user-management"]');
|
|
|
|
// 找到测试用户并修改其权限
|
|
const testUserRow = page
|
|
.locator('.ant-table-tbody tr')
|
|
.filter({ hasText: TEST_CONFIG.testUser.username });
|
|
if ((await testUserRow.count()) > 0) {
|
|
await testUserRow.locator('[data-testid="assign-role"]').click();
|
|
|
|
// 分配新的角色权限
|
|
await page.check('[data-testid="role-admin"]');
|
|
await page.click('[data-testid="save-user-roles"]');
|
|
|
|
await expect(page.locator('.ant-message-success')).toBeVisible();
|
|
}
|
|
|
|
// 切换到测试用户账号(模拟用户刷新或重新登录)
|
|
await page.click('[data-testid="user-dropdown"]');
|
|
await page.click('[data-testid="logout-button"]');
|
|
|
|
await loginAsTestUser(page);
|
|
|
|
// 检查权限是否已更新
|
|
await expect(page.locator('[data-testid="menu-system"]')).toBeVisible();
|
|
});
|
|
|
|
test('权限指令v-permission应该正常工作', async ({ page }) => {
|
|
await page.goto(TEST_CONFIG.baseURL);
|
|
await loginAsTestUser(page);
|
|
|
|
// 访问有使用v-permission指令的页面
|
|
await page.goto(`${TEST_CONFIG.baseURL}/account/list`);
|
|
|
|
// 检查使用v-permission指令的元素是否按权限显示/隐藏
|
|
const createButton = page.locator('[v-permission="account:create"]');
|
|
const viewButton = page.locator('[v-permission="account:view"]');
|
|
|
|
if ((await createButton.count()) > 0) {
|
|
// 如果用户没有创建权限,按钮应该被隐藏
|
|
await expect(createButton).not.toBeVisible();
|
|
}
|
|
|
|
if ((await viewButton.count()) > 0) {
|
|
// 如果用户有查看权限,按钮应该可见
|
|
await expect(viewButton).toBeVisible();
|
|
}
|
|
});
|
|
});
|
|
|
|
// 辅助函数:超级管理员登录
|
|
async function loginAsSuperAdmin(page: Page) {
|
|
await page.fill(
|
|
'[data-testid="username-input"]',
|
|
TEST_CONFIG.superAdmin.username,
|
|
);
|
|
await page.fill(
|
|
'[data-testid="password-input"]',
|
|
TEST_CONFIG.superAdmin.password,
|
|
);
|
|
await page.click('[data-testid="login-button"]');
|
|
await page.waitForURL(/\/dashboard/, { timeout: 10000 });
|
|
}
|
|
|
|
// 辅助函数:测试用户登录
|
|
async function loginAsTestUser(page: Page) {
|
|
await page.fill(
|
|
'[data-testid="username-input"]',
|
|
TEST_CONFIG.testUser.username,
|
|
);
|
|
await page.fill(
|
|
'[data-testid="password-input"]',
|
|
TEST_CONFIG.testUser.password,
|
|
);
|
|
await page.click('[data-testid="login-button"]');
|
|
await page.waitForURL(/\/dashboard/, { timeout: 10000 });
|
|
}
|