Files
clinicpro/assets/admin/pages/HolidaysSettingsPage.test.tsx
hamedandClaude Opus 5 f06efe26c0 fix(holidays): honest dates and reachable fields on the holidays page
The table had two date columns for one date: "تاریخ" printed the raw
1405-05-13 string in Latin digits, and the column labelled "میلادی" ran the
same day through formatDate — which returns Jalali. One date, twice, under a
label that lied. It is now a single formatted Jalali column.

The closure form used a native <input type="date">: Gregorian, an English
mm/dd/yyyy placeholder in an RTL Persian panel, and a white box in dark mode
because a native control does not follow the theme. It is the shared Persian
picker now.

That picker turned out to be a div with an onClick — no role, no tab stop, no
accessible name, and its clear button was a span. Since every page that picks
a date goes through it, it gained role/tabIndex/Enter-Space, an ariaLabel
prop, and a real button for clear. The page passes labels for the year select
and both form fields, and the global topbar search got an aria-label, which
takes the runtime accessibility probe on this page to clean.

useHolidays now returns an error, so a failed request reads as an error
instead of an empty year — previously indistinguishable.

The page had no test file; it has eight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 17:25:56 +03:30

112 lines
4.7 KiB
TypeScript

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(<HolidaysSettingsPage />);
expect(screen.getByText('۱۴۰۵/۰۵/۱۳')).toBeInTheDocument();
expect(screen.queryByText('1405-05-13')).not.toBeInTheDocument();
expect(screen.queryByText('میلادی')).not.toBeInTheDocument();
});
it('روز تعطیل را برای این محیط باز می‌کند', async () => {
const user = userEvent.setup();
renderWithProviders(<HolidaysSettingsPage />);
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(<HolidaysSettingsPage />);
expect(screen.getByText('باز است')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'تعطیل کن' }));
expect(removeOverride.mutate).toHaveBeenCalledWith('o-1');
});
/** بدون این، درخواستِ شکست‌خورده مثل «سالِ خالی» دیده می‌شد. */
it('خطای سرور را نشان می‌دهد، نه سالِ خالی', () => {
error = 'خطای داخلی سرور';
holidays = [];
renderWithProviders(<HolidaysSettingsPage />);
expect(screen.getByText('خطای داخلی سرور')).toBeInTheDocument();
});
it('سالِ خالی را با ارقام فارسی می‌گوید', () => {
holidays = [];
renderWithProviders(<HolidaysSettingsPage />, { route: '/admin/holidays?year=1404' });
expect(screen.getByText('برای سال ۱۴۰۴ تعطیلی ثبت نشده است')).toBeInTheDocument();
});
/** انتخابگر سال و ورودی تاریخ هر دو باید نام دسترس‌پذیر داشته باشند. */
it('فیلدها نام دارند', () => {
renderWithProviders(<HolidaysSettingsPage />);
expect(screen.getByRole('button', { name: 'تاریخ تعطیلی' })).toBeInTheDocument();
expect(screen.getByLabelText('توضیح')).toBeInTheDocument();
});
/** ورودی نیتیو میلادی بود و در دارک‌مود سفید می‌ماند؛ باید رفته باشد. */
it('ورودی تاریخ نیتیو ندارد', () => {
const { container } = renderWithProviders(<HolidaysSettingsPage />);
expect(container.querySelector('input[type="date"]')).toBeNull();
});
it('تعطیلی محیط را با تاریخ و توضیح ثبت می‌کند', async () => {
const user = userEvent.setup();
renderWithProviders(<HolidaysSettingsPage />);
// بدون تاریخ، ثبت ممکن نیست.
expect(screen.getByRole('button', { name: 'افزودن' })).toBeDisabled();
await user.type(screen.getByLabelText('توضیح'), 'تعطیلی داخلی');
expect(screen.getByRole('button', { name: 'افزودن' })).toBeDisabled();
});
});