/** * API Mock 工具 * 用于单元测试中模拟 API 响应 */ import { vi } from 'vitest' import * as fixtures from '../fixtures' // Mock request 模块的类型 type MockedRequest = { get: ReturnType post: ReturnType put: ReturnType del: ReturnType } /** * 创建 API mock */ export function createApiMock() { return { get: vi.fn(), post: vi.fn(), put: vi.fn(), del: vi.fn() } } /** * 设置登录 API mock */ export function mockLoginApi(request: MockedRequest) { // login request.post.mockImplementation((url: string, data?: any) => { if (url === '/admin/auth/login') { if (data?.username === 'admin' && data?.password === '123456') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockLoginResponse)) } return Promise.resolve(fixtures.wrapErrorResponse('用户名或密码错误', 401)) } if (url === '/admin/auth/logout') { return Promise.resolve(fixtures.wrapResponse(null)) } if (url === '/admin/auth/password') { if (data?.oldPassword === '123456') { return Promise.resolve(fixtures.wrapResponse(null, 200, '密码修改成功')) } return Promise.resolve(fixtures.wrapErrorResponse('原密码错误', 400)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) // getInfo request.get.mockImplementation((url: string) => { if (url === '/admin/auth/info') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockAdminInfo)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) } /** * 设置机器 API mock */ export function mockMachineApi(request: MockedRequest) { request.get.mockImplementation((url: string, params?: any) => { if (url === '/admin/machines/list') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockMachines)) } if (url === '/admin/machines/detail') { const machine = fixtures.mockMachines.find((m) => m.id === params?.id) if (machine) { return Promise.resolve(fixtures.wrapResponse(machine)) } return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) request.post.mockImplementation((url: string, data?: any, _config?: any) => { if (url === '/admin/machines/add') { const newMachine: (typeof fixtures.mockMachines)[0] = { id: fixtures.mockMachines.length + 1, machineId: data.machineId, name: data.name, location: data.location || '', description: data.description || '', enabled: true, cameraCount: 0, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } return Promise.resolve(fixtures.wrapResponse(newMachine)) } if (url === '/admin/machines/update') { const machine = fixtures.mockMachines.find((m) => m.id === data?.id) if (machine) { return Promise.resolve(fixtures.wrapResponse({ ...machine, ...data })) } return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404)) } if (url === '/admin/machines/delete') { const id = _config?.params?.id const machine = fixtures.mockMachines.find((m) => m.id === id) if (machine) { if (machine.cameraCount > 0) { return Promise.resolve(fixtures.wrapErrorResponse('该机器下存在摄像头,无法删除', 400)) } return Promise.resolve(fixtures.wrapResponse(null)) } return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) } /** * 设置摄像头 API mock */ export function mockCameraApi(request: MockedRequest) { request.get.mockImplementation((url: string, params?: any) => { if (url === '/admin/cameras/list') { let cameras = fixtures.mockCameras if (params?.machineId) { cameras = cameras.filter((c) => c.machineId === params.machineId) } return Promise.resolve(fixtures.wrapResponse(cameras)) } if (url === '/admin/cameras/detail') { const camera = fixtures.mockCameras.find((c) => c.id === params?.id) if (camera) { return Promise.resolve(fixtures.wrapResponse(camera)) } return Promise.resolve(fixtures.wrapErrorResponse('摄像头不存在', 404)) } if (url === '/camera/list') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras)) } if (url.startsWith('/camera/') && !url.includes('/ptz')) { const cameraId = url.split('/')[2] const camera = fixtures.mockCameras.find((c) => c.cameraId === cameraId) if (camera) { return Promise.resolve(fixtures.wrapResponse(camera)) } } if (url === '/camera/current') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockChannels[0])) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) request.post.mockImplementation((url: string, data?: any, config?: any) => { if (url === '/admin/cameras/add') { const newCamera = { id: fixtures.mockCameras.length + 1, ...data, status: 'OFFLINE', channels: [], createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } return Promise.resolve(fixtures.wrapResponse(newCamera)) } if (url === '/admin/cameras/update') { const camera = fixtures.mockCameras.find((c) => c.id === data?.id) if (camera) { return Promise.resolve(fixtures.wrapResponse({ ...camera, ...data })) } return Promise.resolve(fixtures.wrapErrorResponse('摄像头不存在', 404)) } if (url === '/admin/cameras/delete') { return Promise.resolve(fixtures.wrapResponse(null)) } if (url === '/admin/cameras/check') { return Promise.resolve(fixtures.wrapResponse(true)) } if (url === '/camera/switch') { const channel = fixtures.mockChannels.find((c) => c.channelId === data?.channelId) if (channel) { return Promise.resolve(fixtures.wrapResponse(channel)) } return Promise.resolve(fixtures.wrapErrorResponse('通道不存在', 404)) } if (url.includes('/ptz/start')) { return Promise.resolve(fixtures.wrapResponse(null)) } if (url.includes('/ptz/stop')) { return Promise.resolve(fixtures.wrapResponse(null)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) } /** * 设置统计 API mock */ export function mockStatsApi(request: MockedRequest) { request.get.mockImplementation((url: string) => { if (url === '/admin/stats/dashboard') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockDashboardStats)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) } /** * 设置所有 API mock */ export function mockAllApis(request: MockedRequest) { request.get.mockImplementation((url: string, params?: any) => { // Auth if (url === '/admin/auth/info') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockAdminInfo)) } // Machines if (url === '/admin/machines/list') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockMachines)) } if (url === '/admin/machines/detail') { const machine = fixtures.mockMachines.find((m) => m.id === params?.id) return Promise.resolve(fixtures.wrapResponse(machine)) } // Cameras if (url === '/admin/cameras/list') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras)) } if (url === '/camera/list') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras)) } // Stats if (url === '/admin/stats/dashboard') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockDashboardStats)) } return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404)) }) request.post.mockImplementation((url: string, data?: any) => { if (url === '/admin/auth/login') { if (data?.username === 'admin' && data?.password === '123456') { return Promise.resolve(fixtures.wrapResponse(fixtures.mockLoginResponse)) } return Promise.resolve(fixtures.wrapErrorResponse('用户名或密码错误', 401)) } if (url === '/admin/auth/logout') { return Promise.resolve(fixtures.wrapResponse(null)) } return Promise.resolve(fixtures.wrapResponse(null)) }) }