import { describe, it, expect, vi, beforeEach } from 'vitest'; // --- clinicApi (native fetch) --- import { getClinicDoctors } from '@/services/clinicApi'; describe('getClinicDoctors', () => { beforeEach(() => vi.stubGlobal('fetch', vi.fn())); it('پاسخ double-nested → { data, page }', async () => { fetch.mockResolvedValue({ ok: true, json: () => Promise.resolve({ data: { data: [{ uuid: 'd1' }, { uuid: 'd2' }], meta: { totalPages: 3, currentPage: 1 } }, }), }); const out = await getClinicDoctors('my-clinic', { page: 1 }); expect(out.data).toHaveLength(2); expect(out.page).toEqual({ total_pages: 3, current: 1 }); const calledUrl = fetch.mock.calls[0][0]; expect(calledUrl).toContain('/api/v1/clinic/doctor-list/my-clinic'); }); it('بدون meta → صفحه‌بندی پیش‌فرض', async () => { fetch.mockResolvedValue({ ok: true, json: () => Promise.resolve({ data: { data: [] } }) }); const out = await getClinicDoctors('x'); expect(out.page).toEqual({ total_pages: 1, current: 1 }); }); it('پاسخ ناموفق (ok=false) → shape خالی پیش‌فرض', async () => { fetch.mockResolvedValue({ ok: false, status: 500, text: () => Promise.resolve('err') }); const out = await getClinicDoctors('x'); expect(out).toEqual({ data: [], page: { total_pages: 1, current: 1 } }); }); it('خطای شبکه → shape خالی پیش‌فرض', async () => { fetch.mockRejectedValue(new Error('net')); const out = await getClinicDoctors('x'); expect(out.data).toEqual([]); }); }); // --- response.js wrappers (mock axios layer) --- vi.mock('@/services/api', () => ({ default: { get: vi.fn(() => Promise.resolve({})), post: vi.fn(() => Promise.resolve({})), patch: vi.fn(() => Promise.resolve({})), delete: vi.fn(() => Promise.resolve({})), }, })); import api from '@/services/api'; import { request } from '@/services/response'; describe('request wrappers — قرارداد به لایه‌ی API', () => { beforeEach(() => { api.get.mockClear(); api.post.mockClear(); }); it('getUserProfile → GET مسیر درست با requireAuth', () => { request.getUserProfile('u1'); expect(api.get).toHaveBeenCalledWith('/api/v1/user-profile/u1', { requireAuth: true }); }); it('getUserInfo → GET oauth/userinfo با requireAuth', () => { request.getUserInfo(); expect(api.get).toHaveBeenCalledWith('oauth/userinfo', { requireAuth: true }); }); it('postAppointment → POST با body و requireAuth', () => { request.postAppointment({ slot: 5 }); expect(api.post).toHaveBeenCalledWith('api/v1/appointment', { slot: 5 }, { requireAuth: true }); }); // --- نوبت‌دهی منبع‌محور --- it('getBookingResources → بدون کلینیک، مسیر ساده', () => { request.getBookingResources('doc-1'); expect(api.get.mock.calls[0][0]).toBe('api/v1/appointment-booking-resources/doc-1'); }); it('getBookingResources → با کلینیک، clinic_uuid با ? می‌آید', () => { request.getBookingResources('doc-1', 'cl-1'); expect(api.get.mock.calls[0][0]).toBe( 'api/v1/appointment-booking-resources/doc-1?clinic_uuid=cl-1' ); }); it('getResourceSlots → هر سرویس یک service_item_uuids[] جدا می‌گیرد', () => { request.getResourceSlots('res-1', '2026-08-10', ['s1', 's2']); const url = api.get.mock.calls[0][0]; expect(url).toContain('resource_uuid=res-1'); expect(url).toContain('date=2026-08-10'); expect(url).toContain('&service_item_uuids[]=s1'); expect(url).toContain('&service_item_uuids[]=s2'); }); it('getResourceSlots → uuid با کاراکتر ویژه encode می‌شود', () => { request.getResourceSlots('res-1', '2026-08-10', ['a/b']); expect(api.get.mock.calls[0][0]).toContain('service_item_uuids[]=a%2Fb'); }); it('getResourceSlots → فهرست خالی هیچ پارامتر سرویسی نمی‌سازد', () => { request.getResourceSlots('res-1', '2026-08-10', []); expect(api.get.mock.calls[0][0]).not.toContain('service_item_uuids'); }); it('getResourceMonthAvailability → سال و ماه و سرویس‌ها در query', () => { request.getResourceMonthAvailability('res-1', 2026, 9, ['s1']); const url = api.get.mock.calls[0][0]; expect(url).toContain('api/v1/appointment-resource-month-availability/res-1'); expect(url).toContain('year=2026'); expect(url).toContain('month=9'); expect(url).toContain('&service_item_uuids[]=s1'); }); it('هر سه اندپوینت عمومی‌اند — هدر Authorization حذف می‌شود', () => { request.getBookingResources('doc-1'); request.getResourceSlots('res-1', '2026-08-10', ['s1']); request.getResourceMonthAvailability('res-1', 2026, 9, ['s1']); for (const call of api.get.mock.calls) { expect(call[1]?.headers?.Authorization).toBe(''); } }); });