- Updated DoctorPage component to accept bookingResources prop for appointment list. - Added serviceQuery function to serialize service item UUIDs for API requests. - Introduced new API endpoints for fetching booking resources and resource slots. - Enhanced tests for new resource-based booking functionality, including resource selection and service availability. - Created ResourceSelect component for selecting appointment types, including doctor and resource options. - Updated appointment submission logic to include resource_uuid in payload when applicable. - Ensured UI reflects changes in booking flow without disrupting existing doctor-centric experience.
129 lines
5.3 KiB
JavaScript
129 lines
5.3 KiB
JavaScript
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('');
|
|
}
|
|
});
|
|
});
|