import { describe, it, expect, beforeEach, vi } from 'vitest'; import '../helpers/mock-api'; import { api } from '@/services/request'; import { listAppointments, getAppointment, createAppointment, cancelAppointment, getDoctorSchedules, listDoctors, calendarView, } from '@/services/appointment'; describe('appointment service', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('listAppointments', () => { it('无 patientId 时传递分页参数', async () => { const mock = { data: [], total: 0 }; vi.mocked(api.get).mockResolvedValueOnce(mock); await listAppointments(); expect(api.get).toHaveBeenCalledWith('/health/appointments', { page: 1, page_size: 20, }); }); it('有 patientId 时附加 patient_id', async () => { vi.mocked(api.get).mockResolvedValueOnce({ data: [], total: 0 }); await listAppointments('p-123'); expect(api.get).toHaveBeenCalledWith('/health/appointments', { page: 1, page_size: 20, patient_id: 'p-123', }); }); }); describe('getAppointment', () => { it('调用 api.get 拼接 ID', async () => { const mock = { id: 'a-1', status: 'confirmed', version: 1 } as any; vi.mocked(api.get).mockResolvedValueOnce(mock); const result = await getAppointment('a-1'); expect(api.get).toHaveBeenCalledWith('/health/appointments/a-1'); expect(result).toEqual(mock); }); }); describe('createAppointment', () => { it('调用 api.post 传递预约数据', async () => { const input = { patient_id: 'p-1', doctor_id: 'd-1', appointment_date: '2026-06-01', start_time: '09:00', end_time: '09:30', }; vi.mocked(api.post).mockResolvedValueOnce({ id: 'ap-1', ...input }); await createAppointment(input); expect(api.post).toHaveBeenCalledWith('/health/appointments', input); }); }); describe('cancelAppointment', () => { it('调用 api.put 传递 cancelled 状态和 version', async () => { vi.mocked(api.put).mockResolvedValueOnce({}); await cancelAppointment('ap-1', 2); expect(api.put).toHaveBeenCalledWith('/health/appointments/ap-1/status', { status: 'cancelled', version: 2, }); }); }); describe('getDoctorSchedules', () => { it('返回排班并计算 available_count', async () => { vi.mocked(api.get).mockResolvedValueOnce({ data: [ { id: 's-1', doctor_id: 'd-1', date: '2026-06-01', start_time: '09:00', end_time: '12:00', max_appointments: 10, current_appointments: 3 }, ], total: 1, }); const result = await getDoctorSchedules('d-1', '2026-06-01', '2026-06-07'); expect(result.data[0].available_count).toBe(7); }); }); describe('listDoctors', () => { it('无 department 时获取全部', async () => { vi.mocked(api.get).mockResolvedValueOnce({ data: [], total: 0 }); await listDoctors(); expect(api.get).toHaveBeenCalledWith('/health/doctors', { page_size: 100 }); }); it('有 department 时过滤', async () => { vi.mocked(api.get).mockResolvedValueOnce({ data: [], total: 0 }); await listDoctors('内科'); expect(api.get).toHaveBeenCalledWith('/health/doctors', { page_size: 100, department: '内科', }); }); }); describe('calendarView', () => { it('展平嵌套结构并计算 available_count', async () => { vi.mocked(api.get).mockResolvedValueOnce([ { date: '2026-06-01', schedules: [ { id: 's-1', doctor_id: 'd-1', start_time: '09:00', end_time: '12:00', max_appointments: 5, current_appointments: 2 }, ], }, { date: '2026-06-02', schedules: [ { id: 's-2', doctor_id: 'd-1', start_time: '14:00', end_time: '17:00', max_appointments: 8, current_appointments: 1 }, ], }, ] as any); const result = await calendarView('2026-06-01', '2026-06-07'); expect(result).toHaveLength(2); expect(result[0].available_count).toBe(3); expect(result[1].available_count).toBe(7); expect(result[0].date).toBe('2026-06-01'); }); }); });