feat: 实现角色定义系统

- 创建角色定义基类 RoleDefinition
- 实现管理员角色 AdminRole
- 实现普通用户角色 UserRole
- 实现测试用户角色 TestRole
- 实现角色工厂 RoleFactory
- 添加完整的单元测试
- 更新 vitest 配置以包含角色定义测试

所有角色统一使用密码: Test@123
This commit is contained in:
张翔
2026-04-04 20:43:25 +08:00
parent 4732b9ef02
commit 54ea704f27
9 changed files with 203 additions and 3 deletions
@@ -0,0 +1,24 @@
import { describe, it, expect } from 'vitest';
import { AdminRole } from '../admin.role';
describe('AdminRole', () => {
it('should have admin credentials', () => {
expect(AdminRole.name).toBe('admin');
expect(AdminRole.displayName).toBe('超级管理员');
expect(AdminRole.credentials.username).toBe('admin');
expect(AdminRole.credentials.password).toBe('Test@123');
});
it('should have all permissions', () => {
expect(AdminRole.permissions).toContain('user:*');
expect(AdminRole.permissions).toContain('role:*');
expect(AdminRole.permissions).toContain('menu:*');
expect(AdminRole.cannotAccess).toHaveLength(0);
});
it('should be able to create all resources', () => {
expect(AdminRole.expectedBehaviors.canCreate).toContain('user');
expect(AdminRole.expectedBehaviors.canCreate).toContain('role');
expect(AdminRole.expectedBehaviors.canCreate).toContain('menu');
});
});
@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import type { RoleDefinition } from '../base.role';
describe('RoleDefinition', () => {
it('should define required role properties', () => {
const role: RoleDefinition = {
name: 'test',
displayName: '测试角色',
credentials: {
username: 'testuser',
password: 'Test@123'
},
permissions: ['test:read', 'test:write'],
cannotAccess: ['/admin'],
expectedBehaviors: {
canCreate: ['test'],
canRead: ['test'],
canUpdate: ['test'],
canDelete: []
}
};
expect(role.name).toBe('test');
expect(role.displayName).toBe('测试角色');
expect(role.credentials.username).toBe('testuser');
expect(role.credentials.password).toBe('Test@123');
expect(role.permissions).toHaveLength(2);
expect(role.cannotAccess).toHaveLength(1);
});
});
@@ -0,0 +1,28 @@
import { describe, it, expect } from 'vitest';
import { RoleFactory } from '../role-factory';
describe('RoleFactory', () => {
it('should get admin role', () => {
const role = RoleFactory.getRole('admin');
expect(role.name).toBe('admin');
expect(role.credentials.username).toBe('admin');
});
it('should get user role', () => {
const role = RoleFactory.getRole('user');
expect(role.name).toBe('user');
expect(role.credentials.username).toBe('normaluser');
});
it('should throw error for unknown role', () => {
expect(() => RoleFactory.getRole('unknown')).toThrow("Role 'unknown' not found");
});
it('should get all roles', () => {
const roles = RoleFactory.getAllRoles();
expect(roles).toHaveLength(3);
expect(roles.map(r => r.name)).toContain('admin');
expect(roles.map(r => r.name)).toContain('user');
expect(roles.map(r => r.name)).toContain('test');
});
});
@@ -0,0 +1,25 @@
import type { RoleDefinition } from './base.role';
export const AdminRole: RoleDefinition = {
name: 'admin',
displayName: '超级管理员',
credentials: {
username: 'admin',
password: 'Test@123'
},
permissions: [
'user:*',
'role:*',
'menu:*',
'config:*',
'log:read',
'dict:*'
],
cannotAccess: [],
expectedBehaviors: {
canCreate: ['user', 'role', 'menu', 'config', 'dict'],
canRead: ['user', 'role', 'menu', 'config', 'dict', 'log'],
canUpdate: ['user', 'role', 'menu', 'config', 'dict'],
canDelete: ['user', 'role', 'menu', 'config', 'dict']
}
};
@@ -0,0 +1,16 @@
export interface RoleDefinition {
name: string;
displayName: string;
credentials: {
username: string;
password: string;
};
permissions: string[];
cannotAccess: string[];
expectedBehaviors: {
canCreate: string[];
canRead: string[];
canUpdate: string[];
canDelete: string[];
};
}
@@ -0,0 +1,24 @@
import type { RoleDefinition } from './base.role';
import { AdminRole } from './admin.role';
import { UserRole } from './user.role';
import { TestRole } from './test.role';
export class RoleFactory {
private static roles: Map<string, RoleDefinition> = new Map([
['admin', AdminRole],
['user', UserRole],
['test', TestRole]
]);
static getRole(roleName: string): RoleDefinition {
const role = this.roles.get(roleName);
if (!role) {
throw new Error(`Role '${roleName}' not found`);
}
return role;
}
static getAllRoles(): RoleDefinition[] {
return Array.from(this.roles.values());
}
}
@@ -0,0 +1,24 @@
import type { RoleDefinition } from './base.role';
export const TestRole: RoleDefinition = {
name: 'test',
displayName: '测试用户',
credentials: {
username: 'e2e_test_user',
password: 'Test@123'
},
permissions: [
'test:read',
'test:write'
],
cannotAccess: [
'/user-management',
'/role-management'
],
expectedBehaviors: {
canCreate: ['test'],
canRead: ['test'],
canUpdate: ['test'],
canDelete: []
}
};
@@ -0,0 +1,26 @@
import type { RoleDefinition } from './base.role';
export const UserRole: RoleDefinition = {
name: 'user',
displayName: '普通用户',
credentials: {
username: 'normaluser',
password: 'Test@123'
},
permissions: [
'user:read:self',
'user:update:self'
],
cannotAccess: [
'/user-management',
'/role-management',
'/menu-management',
'/system-config'
],
expectedBehaviors: {
canCreate: [],
canRead: ['self'],
canUpdate: ['self'],
canDelete: []
}
};
+6 -3
View File
@@ -8,13 +8,16 @@ export default defineConfig({
globals: true,
environment: 'jsdom',
setupFiles: ['./src/test/setup.ts'],
// 明确指定包含单元测试文件
include: ['src/test/**/*.{test,spec}.{js,ts,jsx,tsx}'],
// 明确指定包含单元测试文件和角色定义测试
include: [
'src/test/**/*.{test,spec}.{js,ts,jsx,tsx}',
'e2e/role-based-tests/**/__tests__/*.{test,spec}.{js,ts,jsx,tsx}'
],
// 明确排除E2E测试文件
exclude: [
'node_modules/',
'dist/',
'e2e/**/*',
'e2e/**/*.spec.ts',
'**/*.d.ts',
'**/*.config.*',
'**/mockData',