import { describe, it, expect, vi, beforeEach } from 'vitest'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { renderWithProviders } from '../test/utils'; vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } })); vi.mock('../hooks/usePermissions', () => ({ usePermissions: () => ({ can: () => true }) })); const setOverride = { mutate: vi.fn(), isPending: false }; const removeOverride = { mutate: vi.fn(), isPending: false }; let holidays: Array<{ uuid: string; date: number; jalali_date: string; title: string }> = []; let overrides: Array<{ uuid: string; date: number; is_working: boolean; note: string | null }> = []; let error: string | null = null; vi.mock('../hooks/useResourceCalendar', () => ({ useHolidays: () => ({ holidays, overrides, loading: false, error, setOverride, removeOverride }), })); import HolidaysSettingsPage from './HolidaysSettingsPage'; // ۱۴۰۵-۰۵-۱۳ ⇒ ۲۰۲۶-۰۸-۰۴ const MARTYRDOM = { uuid: 'h-1', date: Math.floor(new Date(2026, 7, 4).getTime() / 1000), jalali_date: '1405-05-13', title: 'شهادت', }; describe('HolidaysSettingsPage', () => { beforeEach(() => { holidays = [MARTYRDOM]; overrides = []; error = null; vi.clearAllMocks(); }); /** * پیش‌تر دو ستون تاریخ بود: «تاریخ» رشتهٔ خامِ `1405-05-13` و «میلادی» که با * formatDate همان روز را **شمسی** می‌داد. یک تاریخ، دو بار، با برچسبی که دروغ می‌گفت. */ it('یک ستون تاریخ دارد و شمسی است، نه رشتهٔ خام', () => { renderWithProviders(); expect(screen.getByText('۱۴۰۵/۰۵/۱۳')).toBeInTheDocument(); expect(screen.queryByText('1405-05-13')).not.toBeInTheDocument(); expect(screen.queryByText('میلادی')).not.toBeInTheDocument(); }); it('روز تعطیل را برای این محیط باز می‌کند', async () => { const user = userEvent.setup(); renderWithProviders(); await user.click(screen.getByRole('button', { name: 'این روز باز است' })); expect(setOverride.mutate).toHaveBeenCalledWith({ date: MARTYRDOM.date, is_working: true }); }); it('روزِ استثنا خورده را دوباره تعطیل می‌کند', async () => { overrides = [{ uuid: 'o-1', date: MARTYRDOM.date, is_working: true, note: null }]; const user = userEvent.setup(); renderWithProviders(); expect(screen.getByText('باز است')).toBeInTheDocument(); await user.click(screen.getByRole('button', { name: 'تعطیل کن' })); expect(removeOverride.mutate).toHaveBeenCalledWith('o-1'); }); /** بدون این، درخواستِ شکست‌خورده مثل «سالِ خالی» دیده می‌شد. */ it('خطای سرور را نشان می‌دهد، نه سالِ خالی', () => { error = 'خطای داخلی سرور'; holidays = []; renderWithProviders(); expect(screen.getByText('خطای داخلی سرور')).toBeInTheDocument(); }); it('سالِ خالی را با ارقام فارسی می‌گوید', () => { holidays = []; renderWithProviders(, { route: '/admin/holidays?year=1404' }); expect(screen.getByText('برای سال ۱۴۰۴ تعطیلی ثبت نشده است')).toBeInTheDocument(); }); /** انتخابگر سال و ورودی تاریخ هر دو باید نام دسترس‌پذیر داشته باشند. */ it('فیلدها نام دارند', () => { renderWithProviders(); expect(screen.getByRole('button', { name: 'تاریخ تعطیلی' })).toBeInTheDocument(); expect(screen.getByLabelText('توضیح')).toBeInTheDocument(); }); /** ورودی نیتیو میلادی بود و در دارک‌مود سفید می‌ماند؛ باید رفته باشد. */ it('ورودی تاریخ نیتیو ندارد', () => { const { container } = renderWithProviders(); expect(container.querySelector('input[type="date"]')).toBeNull(); }); it('تعطیلی محیط را با تاریخ و توضیح ثبت می‌کند', async () => { const user = userEvent.setup(); renderWithProviders(); // بدون تاریخ، ثبت ممکن نیست. expect(screen.getByRole('button', { name: 'افزودن' })).toBeDisabled(); await user.type(screen.getByLabelText('توضیح'), 'تعطیلی داخلی'); expect(screen.getByRole('button', { name: 'افزودن' })).toBeDisabled(); }); });