/** * patients API 契约测试 * * 验证 patientApi 各函数调用正确的 HTTP 方法、URL 路径和参数序列化。 */ 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 { patientApi } from './patients' beforeEach(() => { vi.clearAllMocks() }) describe('patientApi', () => { const fakeRes = { data: { success: true, data: {} } } it('list 应调用 GET /health/patients 并传递查询参数', async () => { mockGet.mockResolvedValue(fakeRes) await patientApi.list({ page: 1, page_size: 20, search: '张三', status: 'active' }) expect(mockGet).toHaveBeenCalledWith('/health/patients', { params: { page: 1, page_size: 20, search: '张三', status: 'active' }, }) }) it('list 应支持 tag_id 过滤参数', async () => { mockGet.mockResolvedValue(fakeRes) await patientApi.list({ tag_id: 'tag-001' }) expect(mockGet).toHaveBeenCalledWith('/health/patients', { params: { tag_id: 'tag-001' }, }) }) it('get 应调用 GET /health/patients/:id', async () => { mockGet.mockResolvedValue(fakeRes) await patientApi.get('p-001') expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001') }) it('create 应调用 POST /health/patients 并传递请求体', async () => { mockPost.mockResolvedValue(fakeRes) const req = { name: '李四', gender: 'male', birth_date: '1990-01-01' } await patientApi.create(req) expect(mockPost).toHaveBeenCalledWith('/health/patients', req) }) it('update 应调用 PUT /health/patients/:id 并传递请求体含 version', async () => { mockPut.mockResolvedValue(fakeRes) const req = { name: '李四改', version: 2 } await patientApi.update('p-001', req) expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001', req) }) it('delete 应调用 DELETE /health/patients/:id 并在 body 中传递 version', async () => { mockDelete.mockResolvedValue(undefined) await patientApi.delete('p-001', 3) expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001', { data: { version: 3 }, }) }) it('manageTags 应调用 POST /health/patients/:id/tags 并传递 tag_ids', async () => { mockPost.mockResolvedValue(undefined) await patientApi.manageTags('p-001', ['tag-1', 'tag-2']) expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/tags', { tag_ids: ['tag-1', 'tag-2'], }) }) it('listFamilyMembers 应调用 GET /health/patients/:id/family-members', async () => { mockGet.mockResolvedValue(fakeRes) await patientApi.listFamilyMembers('p-001') expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/family-members') }) it('createFamilyMember 应调用 POST /health/patients/:id/family-members', async () => { mockPost.mockResolvedValue(fakeRes) const req = { name: '家属A', relationship: 'spouse', phone: '13800138000' } await patientApi.createFamilyMember('p-001', req) expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/family-members', req) }) it('updateFamilyMember 应调用 PUT /health/patients/:pid/family-members/:mid', async () => { mockPut.mockResolvedValue(fakeRes) const req = { name: '家属A改', version: 1 } await patientApi.updateFamilyMember('p-001', 'fm-001', req) expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001/family-members/fm-001', req) }) it('deleteFamilyMember 应调用 DELETE /health/patients/:pid/family-members/:mid', async () => { mockDelete.mockResolvedValue(undefined) await patientApi.deleteFamilyMember('p-001', 'fm-001') expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001/family-members/fm-001') }) it('listTags 应调用 GET /health/patient-tags', async () => { mockGet.mockResolvedValue(fakeRes) await patientApi.listTags() expect(mockGet).toHaveBeenCalledWith('/health/patient-tags') }) })