/** * AI 模块 API 契约测试(analysis + prompts + suggestions + usage) */ import { describe, it, expect, vi, beforeEach } from 'vitest' const mockGet = vi.fn() const mockPost = vi.fn() const mockPut = vi.fn() const mockDelete = vi.fn() vi.mock('../client', () => ({ default: { get: (...args: unknown[]) => mockGet(...args), post: (...args: unknown[]) => mockPost(...args), put: (...args: unknown[]) => mockPut(...args), delete: (...args: unknown[]) => mockDelete(...args), }, })) import { analysisApi } from './analysis' import { promptApi } from './prompts' import { suggestionApi } from './suggestions' import { usageApi } from './usage' beforeEach(() => { vi.clearAllMocks() }) describe('analysisApi', () => { const fakeRes = { data: { data: {} } } it('list 应调用 GET /ai/analysis/history 并传递查询参数', async () => { mockGet.mockResolvedValue(fakeRes) await analysisApi.list({ patient_id: 'p-001', analysis_type: 'lab-report', page: 1, page_size: 10 }) expect(mockGet).toHaveBeenCalledWith('/ai/analysis/history', { params: { patient_id: 'p-001', analysis_type: 'lab-report', page: 1, page_size: 10 }, }) }) it('get 应调用 GET /ai/analysis/:id', async () => { mockGet.mockResolvedValue(fakeRes) await analysisApi.get('ana-001') expect(mockGet).toHaveBeenCalledWith('/ai/analysis/ana-001') }) }) describe('promptApi', () => { const fakeRes = { data: { data: {} } } it('list 应调用 GET /ai/prompts 并传递查询参数', async () => { mockGet.mockResolvedValue(fakeRes) await promptApi.list({ category: 'analysis', page: 1, page_size: 10 }) expect(mockGet).toHaveBeenCalledWith('/ai/prompts', { params: { category: 'analysis', page: 1, page_size: 10 }, }) }) it('create 应调用 POST /ai/prompts 并传递请求体', async () => { mockPost.mockResolvedValue(fakeRes) const req = { name: '化验解读', system_prompt: '你是专业医生', user_prompt_template: '解读: {report}', model_config: {}, category: 'analysis' } await promptApi.create(req) expect(mockPost).toHaveBeenCalledWith('/ai/prompts', req) }) it('activate 应调用 POST /ai/prompts/:id/activate', async () => { mockPost.mockResolvedValue(fakeRes) await promptApi.activate('prompt-001') expect(mockPost).toHaveBeenCalledWith('/ai/prompts/prompt-001/activate') }) it('rollback 应调用 POST /ai/prompts/:id/rollback', async () => { mockPost.mockResolvedValue(fakeRes) await promptApi.rollback('prompt-001') expect(mockPost).toHaveBeenCalledWith('/ai/prompts/prompt-001/rollback') }) }) describe('suggestionApi', () => { const fakeRes = { data: { data: {} } } it('list 应调用 GET /ai/suggestions 并传递查询参数', async () => { mockGet.mockResolvedValue(fakeRes) await suggestionApi.list({ analysis_id: 'ana-001', status: 'pending' }) expect(mockGet).toHaveBeenCalledWith('/ai/suggestions', { params: { analysis_id: 'ana-001', status: 'pending' }, }) }) it('approve 应调用 POST /ai/suggestions/:id/approve 并传递 action', async () => { mockPost.mockResolvedValue(fakeRes) await suggestionApi.approve('sug-001', 'approve') expect(mockPost).toHaveBeenCalledWith('/ai/suggestions/sug-001/approve', { action: 'approve' }) }) it('getComparison 应调用 GET /ai/suggestions/:id/comparison', async () => { mockGet.mockResolvedValue(fakeRes) await suggestionApi.getComparison('sug-001') expect(mockGet).toHaveBeenCalledWith('/ai/suggestions/sug-001/comparison') }) }) describe('usageApi', () => { const fakeRes = { data: { data: {} } } it('overview 应调用 GET /ai/usage/overview', async () => { mockGet.mockResolvedValue(fakeRes) await usageApi.overview() expect(mockGet).toHaveBeenCalledWith('/ai/usage/overview') }) it('byType 应调用 GET /ai/usage/by-type', async () => { mockGet.mockResolvedValue(fakeRes) await usageApi.byType() expect(mockGet).toHaveBeenCalledWith('/ai/usage/by-type') }) })