feat: 实现角色定义系统
- 创建角色定义基类 RoleDefinition - 实现管理员角色 AdminRole - 实现普通用户角色 UserRole - 实现测试用户角色 TestRole - 实现角色工厂 RoleFactory - 添加完整的单元测试 - 更新 vitest 配置以包含角色定义测试 所有角色统一使用密码: Test@123
This commit is contained in:
@@ -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: []
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -8,13 +8,16 @@ export default defineConfig({
|
|||||||
globals: true,
|
globals: true,
|
||||||
environment: 'jsdom',
|
environment: 'jsdom',
|
||||||
setupFiles: ['./src/test/setup.ts'],
|
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测试文件
|
// 明确排除E2E测试文件
|
||||||
exclude: [
|
exclude: [
|
||||||
'node_modules/',
|
'node_modules/',
|
||||||
'dist/',
|
'dist/',
|
||||||
'e2e/**/*',
|
'e2e/**/*.spec.ts',
|
||||||
'**/*.d.ts',
|
'**/*.d.ts',
|
||||||
'**/*.config.*',
|
'**/*.config.*',
|
||||||
'**/mockData',
|
'**/mockData',
|
||||||
|
|||||||
Reference in New Issue
Block a user