import { Page, Route } from '@playwright/test'; /** * Mock管理器 * 提供统一的API Mock功能 */ export interface MockConfig { url: string | RegExp; method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; status?: number; body?: unknown; headers?: Record; delay?: number; } export class MockManager { private page: Page; private mocks: Map = new Map(); private isEnabled: boolean = false; constructor(page: Page) { this.page = page; } /** * 启用Mock */ enable(): void { this.isEnabled = true; } /** * 禁用Mock */ disable(): void { this.isEnabled = false; } /** * 检查Mock是否启用 */ isMockEnabled(): boolean { return this.isEnabled; } /** * 添加Mock配置 */ addMock(config: MockConfig): void { const key = this.getMockKey(config.url, config.method || 'GET'); this.mocks.set(key, config); } /** * 移除Mock配置 */ removeMock(url: string | RegExp, method: string = 'GET'): void { const key = this.getMockKey(url, method); this.mocks.delete(key); } /** * 清除所有Mock */ clearMocks(): void { this.mocks.clear(); } /** * 应用所有Mock */ async applyMocks(): Promise { if (!this.isEnabled) { return; } await this.page.route('**/*', async (route: Route) => { const request = route.request(); const url = request.url(); const method = request.method(); // 查找匹配的Mock配置 for (const config of this.mocks.values()) { if (this.matchesUrl(url, config.url) && method === (config.method || 'GET')) { // 模拟延迟 if (config.delay) { await new Promise(resolve => setTimeout(resolve, config.delay)); } // 返回Mock响应 await route.fulfill({ status: config.status || 200, contentType: 'application/json', headers: config.headers || {}, body: JSON.stringify(config.body || {}), }); return; } } // 没有匹配的Mock,继续正常请求 await route.continue(); }); } /** * Mock登录API */ mockLogin(success: boolean = true, delay: number = 500): void { this.addMock({ url: /.*\/auth\/login/, method: 'POST', status: success ? 200 : 401, delay, body: success ? { token: 'mock-token-' + Date.now(), refreshToken: 'mock-refresh-token', user: { id: 1, username: 'admin', realName: '管理员', email: 'admin@example.com', avatar: '', status: 'active', }, permissions: ['*'], } : { message: '用户名或密码错误', code: 401, }, }); } /** * Mock用户列表API */ mockUserList(count: number = 10, delay: number = 300): void { const users = Array.from({ length: count }, (_, i) => ({ id: i + 1, username: `user${i + 1}`, realName: `用户${i + 1}`, email: `user${i + 1}@example.com`, phone: `138001380${String(i).padStart(2, '0')}`, status: i % 3 === 0 ? 'inactive' : 'active', createTime: new Date().toISOString(), })); this.addMock({ url: /.*\/user\/list/, method: 'GET', status: 200, delay, body: { data: users, total: count, page: 1, pageSize: 10, }, }); } /** * Mock角色列表API */ mockRoleList(delay: number = 300): void { const roles = [ { id: 1, roleName: '超级管理员', roleKey: 'admin', status: 'active' }, { id: 2, roleName: '普通用户', roleKey: 'user', status: 'active' }, { id: 3, roleName: '访客', roleKey: 'guest', status: 'inactive' }, ]; this.addMock({ url: /.*\/role\/list/, method: 'GET', status: 200, delay, body: { data: roles, total: roles.length, }, }); } /** * Mock菜单列表API */ mockMenuList(delay: number = 300): void { const menus = [ { id: 1, menuName: '仪表盘', path: '/dashboard', icon: 'DashboardOutlined', status: 'active' }, { id: 2, menuName: '系统管理', path: '/sys', icon: 'SettingOutlined', status: 'active' }, { id: 3, menuName: '用户管理', path: '/sys/user', parentId: 2, status: 'active' }, { id: 4, menuName: '角色管理', path: '/sys/role', parentId: 2, status: 'active' }, ]; this.addMock({ url: /.*\/menu\/list/, method: 'GET', status: 200, delay, body: { data: menus, total: menus.length, }, }); } /** * Mock创建操作 */ mockCreate(resource: string, delay: number = 500): void { this.addMock({ url: new RegExp(`.*\\/${resource}$`), method: 'POST', status: 200, delay, body: { message: '创建成功', code: 200, data: { id: Date.now() }, }, }); } /** * Mock更新操作 */ mockUpdate(resource: string, delay: number = 500): void { this.addMock({ url: new RegExp(`.*\\/${resource}\\/.*`), method: 'PUT', status: 200, delay, body: { message: '更新成功', code: 200, }, }); } /** * Mock删除操作 */ mockDelete(resource: string, delay: number = 500): void { this.addMock({ url: new RegExp(`.*\\/${resource}\\/.*`), method: 'DELETE', status: 200, delay, body: { message: '删除成功', code: 200, }, }); } /** * Mock错误响应 */ mockError(url: string | RegExp, status: number = 500, message: string = '服务器错误'): void { this.addMock({ url, method: 'GET', status, body: { message, code: status, }, }); } /** * Mock网络延迟 */ mockDelay(url: string | RegExp, delay: number = 2000): void { this.addMock({ url, method: 'GET', delay, body: {}, }); } /** * 获取Mock键 */ private getMockKey(url: string | RegExp, method: string): string { const urlStr = url instanceof RegExp ? url.source : url; return `${method}:${urlStr}`; } /** * 检查URL是否匹配 */ private matchesUrl(actualUrl: string, configUrl: string | RegExp): boolean { if (configUrl instanceof RegExp) { return configUrl.test(actualUrl); } return actualUrl.includes(configUrl); } }