import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; vi.mock('@/services/response', () => ({ request: { getServiceSlotsForReschedule: vi.fn(), serviceReschedule: vi.fn(), }, })); import { request } from '@/services/response'; import RescheduleModal from './RescheduleModal'; const appointment = { uuid: 'a-1', doctor: { uuid: 'd-1' }, service_items: [{ uuid: 's-1' }, { uuid: 's-2' }], }; const slots = { data: { total_duration_minutes: 30, start_times: [ { start: 1_900_000_000, end: 1_900_001_800, start_time: '09:00', end_time: '09:30' }, { start: 1_900_003_600, end: 1_900_005_400, start_time: '10:00', end_time: '10:30' }, ], }, }; async function openAndPickFirstDay(user) { render(); await user.click(screen.getByRole('button', { name: 'جابه‌جایی نوبت' })); const days = screen.getAllByRole('button').filter((b) => /\d|[۰-۹]/.test(b.textContent)); await user.click(days[0]); } describe('مودال جابه‌جایی نوبت سایت', () => { beforeEach(() => { request.getServiceSlotsForReschedule.mockResolvedValue(slots); request.serviceReschedule.mockResolvedValue({ data: {} }); }); /** * ⭐ بدون `exclude_appointment_uuid`، بیمار ساعت خودش را «پر» می‌بیند و نمی‌تواند * حتی به همان روز جابه‌جا شود. */ it('وقت‌ها را با کنارگذاشتن نوبت فعلی می‌گیرد', async () => { const user = userEvent.setup(); await openAndPickFirstDay(user); await waitFor(() => expect(request.getServiceSlotsForReschedule).toHaveBeenCalled()); const [doctorUuid, , appointmentUuid, serviceUuids] = request.getServiceSlotsForReschedule.mock.calls[0]; expect(doctorUuid).toBe('d-1'); expect(appointmentUuid).toBe('a-1'); expect(serviceUuids).toEqual(['s-1', 's-2']); }); /** مدت را سرور حساب می‌کند؛ فرانت فقط زمان شروع می‌فرستد. */ it('فقط زمان شروع را می‌فرستد، نه مدت', async () => { const onDone = vi.fn(); const user = userEvent.setup(); render(); await user.click(screen.getByRole('button', { name: 'جابه‌جایی نوبت' })); const days = screen.getAllByRole('button').filter((b) => /\d|[۰-۹]/.test(b.textContent)); await user.click(days[0]); const slot = await screen.findByRole('button', { name: '09:00' }); await user.click(slot); await user.click(screen.getByRole('button', { name: 'جابه‌جا کن' })); await waitFor(() => expect(request.serviceReschedule).toHaveBeenCalledWith('a-1', { start: 1_900_000_000 }), ); await waitFor(() => expect(onDone).toHaveBeenCalled()); }); it('روزِ بدون وقت آزاد را صریح می‌گوید', async () => { request.getServiceSlotsForReschedule.mockResolvedValue({ data: { start_times: [] } }); const user = userEvent.setup(); await openAndPickFirstDay(user); expect(await screen.findByText(/در این روز وقت آزادی نیست/)).toBeInTheDocument(); }); /** ۴۰۹ یعنی همین لحظه کس دیگری گرفت — پیام سرور باید دیده شود. */ it('پیام خطای سرور را نشان می‌دهد', async () => { request.serviceReschedule.mockRejectedValue(new Error('این بازه زمانی قبلاً رزرو شده است')); const user = userEvent.setup(); await openAndPickFirstDay(user); await user.click(await screen.findByRole('button', { name: '09:00' })); await user.click(screen.getByRole('button', { name: 'جابه‌جا کن' })); expect(await screen.findByText('این بازه زمانی قبلاً رزرو شده است')).toBeInTheDocument(); }); });