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: {
getCancellationPreview: vi.fn(),
cancelAppointment: vi.fn(),
},
}));
import { request } from '@/services/response';
import ModalDeleteComment from './index';
const appointment = { uuid: 'a-1', slot_start: 2_000_000_000, status: 'confirmed' };
const preview = (over = {}) => ({
data: {
penalty_rials: 2_500_000,
deposit_refundable: true,
credit_refundable: true,
within_free_window: false,
notes: [],
paid_rials: 5_000_000,
...over,
},
});
describe('مودال لغو نوبت سایت', () => {
beforeEach(() => {
request.cancelAppointment.mockResolvedValue({ data: {} });
});
/** ⭐ تا پیش از این، دکمهٔ تأیید فقط پنجره را میبست و هیچ درخواستی نمیرفت. */
it('پیش از تأیید، جریمه را از سرور نشان میدهد', async () => {
request.getCancellationPreview.mockResolvedValue(preview());
const user = userEvent.setup();
render();
await user.click(screen.getByRole('button', { name: 'لغو کردن نوبت' }));
// ۲٬۵۰۰٬۰۰۰ ریال ⇒ ۲۵۰٬۰۰۰ تومان. قالب رقم به ICU محیط وابسته است، پس فقط
// «مبلغ درست + واحد» سنجیده میشود نه شکل رقمها.
const amount = await screen.findByText(/تومان$/);
expect(amount.textContent.replace(/[^0-9۰-۹٠-٩]/g, '')).toMatch(/2500{2}0|۲۵۰۰۰۰|٢٥٠٠٠٠/);
expect(request.cancelAppointment).not.toHaveBeenCalled();
});
it('در بازهٔ رایگان «بدون جریمه» میگوید، نه صفر', async () => {
request.getCancellationPreview.mockResolvedValue(
preview({ penalty_rials: 0, within_free_window: true }),
);
const user = userEvent.setup();
render();
await user.click(screen.getByRole('button', { name: 'لغو کردن نوبت' }));
expect(await screen.findByText('بدون جریمه')).toBeInTheDocument();
expect(screen.getByText('این لغو در بازهٔ رایگان است.')).toBeInTheDocument();
});
it('تأیید، لغو را واقعاً میفرستد و والد را خبر میکند', async () => {
request.getCancellationPreview.mockResolvedValue(preview());
const onDone = vi.fn();
const user = userEvent.setup();
render();
await user.click(screen.getByRole('button', { name: 'لغو کردن نوبت' }));
await screen.findByText(/جریمهٔ لغو/);
await user.click(screen.getByRole('button', { name: 'لغو نوبت' }));
await waitFor(() =>
expect(request.cancelAppointment).toHaveBeenCalledWith('a-1', { by: 'user' }),
);
await waitFor(() => expect(onDone).toHaveBeenCalled());
});
/** پیشنمایشی که نیامده نباید لغو را قفل کند — ولی باید صریح بگوید نیامده. */
it('نبودِ پیشنمایش، لغو را قفل نمیکند', async () => {
request.getCancellationPreview.mockRejectedValue(new Error('down'));
const user = userEvent.setup();
render();
await user.click(screen.getByRole('button', { name: 'لغو کردن نوبت' }));
expect(await screen.findByText(/پیامد مالی لغو در دسترس نیست/)).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'لغو نوبت' })).not.toBeDisabled();
});
});