import { Page, expect } from '@playwright/test'; import type { RoleDefinition } from '../roles/base.role'; export class PermissionHelper { constructor(private page: Page) {} async verifyCanAccess(path: string): Promise { await this.page.goto(path); await expect(this.page).not.toHaveURL(/\/login/); await expect(this.page).not.toHaveURL(/\/403/); await expect(this.page).not.toHaveURL(/\/404/); } async verifyCannotAccess(path: string): Promise { await this.page.goto(path); // 应该被重定向到登录页或显示403错误 const url = this.page.url(); const isForbidden = url.includes('/403') || url.includes('/login'); expect(isForbidden || await this.isAccessDenied()).toBeTruthy(); } private async isAccessDenied(): Promise { const deniedMessage = this.page.locator('text=/无权限|权限不足|Access Denied|Forbidden/i'); return await deniedMessage.count() > 0; } async verifyCanCreate(resource: string, createButtonSelector: string): Promise { const createButton = this.page.locator(createButtonSelector); await expect(createButton).toBeVisible(); await expect(createButton).toBeEnabled(); } async verifyCannotCreate(resource: string, createButtonSelector: string): Promise { const createButton = this.page.locator(createButtonSelector); const count = await createButton.count(); if (count > 0) { await expect(createButton).not.toBeVisible(); } } async verifyCanEdit(resourceId: string, editButtonSelector: string): Promise { const editButton = this.page.locator(editButtonSelector); await expect(editButton).toBeVisible(); await expect(editButton).toBeEnabled(); } async verifyCannotEdit(resourceId: string, editButtonSelector: string): Promise { const editButton = this.page.locator(editButtonSelector); const count = await editButton.count(); if (count > 0) { await expect(editButton).not.toBeVisible(); } } async verifyCanDelete(resourceId: string, deleteButtonSelector: string): Promise { const deleteButton = this.page.locator(deleteButtonSelector); await expect(deleteButton).toBeVisible(); await expect(deleteButton).toBeEnabled(); } async verifyCannotDelete(resourceId: string, deleteButtonSelector: string): Promise { const deleteButton = this.page.locator(deleteButtonSelector); const count = await deleteButton.count(); if (count > 0) { await expect(deleteButton).not.toBeVisible(); } } async verifyRolePermissions(role: RoleDefinition): Promise { // 验证可访问的路径 for (const path of role.expectedBehaviors.canRead) { if (path !== 'self') { await this.verifyCanAccess(`/${path}`); } } // 验证不可访问的路径 for (const path of role.cannotAccess) { await this.verifyCannotAccess(path); } } async verifyPermissionBoundary( role: RoleDefinition, testScenarios: { resource: string; path: string; createButton?: string; editButton?: string; deleteButton?: string; } ): Promise { await this.page.goto(testScenarios.path); // 验证创建权限 if (testScenarios.createButton) { if (role.expectedBehaviors.canCreate.includes(testScenarios.resource)) { await this.verifyCanCreate(testScenarios.resource, testScenarios.createButton); } else { await this.verifyCannotCreate(testScenarios.resource, testScenarios.createButton); } } // 验证编辑权限 if (testScenarios.editButton) { if (role.expectedBehaviors.canUpdate.includes(testScenarios.resource)) { await this.verifyCanEdit(testScenarios.resource, testScenarios.editButton); } else { await this.verifyCannotEdit(testScenarios.resource, testScenarios.editButton); } } // 验证删除权限 if (testScenarios.deleteButton) { if (role.expectedBehaviors.canDelete.includes(testScenarios.resource)) { await this.verifyCanDelete(testScenarios.resource, testScenarios.deleteButton); } else { await this.verifyCannotDelete(testScenarios.resource, testScenarios.deleteButton); } } } } export function createPermissionHelper(page: Page): PermissionHelper { return new PermissionHelper(page); }