The holiday model was already right — national holidays global, a per-tenant override in both directions, per-doctor and per-resource exceptions — but nothing could create a national holiday. The only writer was an import command, so the calendar the whole product inherits from had no owner. Three admin-only routes give it one. POST upserts, because `date` is unique and re-sending a day should rename it rather than surface a raw database error; PATCH takes only the title, because moving a date means a different holiday. The system admin has no work environment, so the list endpoint now returns the calendar with an empty `overrides` for that role instead of the 403 `pair()` would raise — the person who maintains the calendar has to be able to read it. Both holiday tabs — the doctor's and the resource's — now open with the official calendar above their own exceptions, from one shared card rather than two copies that would drift. Each row can be opted out of with a single click, which is the existing holiday-override endpoint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
3.1 KiB
TypeScript
72 lines
3.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { screen, waitFor } 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() } }));
|
|
|
|
const setOverride = { mutate: vi.fn(), isPending: false };
|
|
const removeOverride = { mutate: vi.fn(), isPending: false };
|
|
|
|
let holidays: Array<{ uuid: string; date: number; title: string }> = [];
|
|
let overrides: Array<{ uuid: string; date: number; is_working: boolean }> = [];
|
|
|
|
vi.mock('../../hooks/useResourceCalendar', () => ({
|
|
useHolidays: () => ({ holidays, overrides, loading: false, setOverride, removeOverride }),
|
|
}));
|
|
|
|
import NationalHolidaysCard from './NationalHolidaysCard';
|
|
|
|
const NOWRUZ = { uuid: 'h-1', date: 1774040400, title: 'نوروز' };
|
|
|
|
describe('NationalHolidaysCard', () => {
|
|
beforeEach(() => {
|
|
holidays = [NOWRUZ];
|
|
overrides = [];
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('تعطیلات رسمی سال را نشان میدهد', () => {
|
|
renderWithProviders(<NationalHolidaysCard canUpdate year={1405} />);
|
|
|
|
expect(screen.getByText(/نوروز/)).toBeInTheDocument();
|
|
expect(screen.getByText('تعطیل')).toBeInTheDocument();
|
|
});
|
|
|
|
/** محیطی که آن روز کار میکند، تعطیلیِ سراسری را برای خودش خنثی میکند. */
|
|
it('با یک کلیک روز را برای این محیط باز میکند', async () => {
|
|
const user = userEvent.setup();
|
|
renderWithProviders(<NationalHolidaysCard canUpdate year={1405} />);
|
|
|
|
await user.click(screen.getByRole('button', { name: 'این روز باز است' }));
|
|
|
|
expect(setOverride.mutate).toHaveBeenCalledWith({ date: NOWRUZ.date, is_working: true });
|
|
});
|
|
|
|
it('روزی که استثنا خورده، «باز» است و میشود دوباره تعطیلش کرد', async () => {
|
|
overrides = [{ uuid: 'o-1', date: NOWRUZ.date, is_working: true }];
|
|
const user = userEvent.setup();
|
|
renderWithProviders(<NationalHolidaysCard canUpdate year={1405} />);
|
|
|
|
expect(screen.getByText('باز')).toBeInTheDocument();
|
|
await user.click(screen.getByRole('button', { name: 'تعطیل کن' }));
|
|
|
|
expect(removeOverride.mutate).toHaveBeenCalledWith('o-1');
|
|
});
|
|
|
|
/** ساخت و حذفِ خودِ تعطیلی کارِ مدیر سیستم است؛ اینجا فقط استثنا زده میشود. */
|
|
it('بدون مجوز ویرایش، هیچ دکمهای نمیدهد', () => {
|
|
renderWithProviders(<NationalHolidaysCard canUpdate={false} year={1405} />);
|
|
|
|
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
expect(screen.getByText('تنظیمات ← تعطیلات رسمی')).toHaveAttribute('href', '/admin/holidays');
|
|
});
|
|
|
|
it('سالِ بدون تعطیلی را صریح میگوید', async () => {
|
|
holidays = [];
|
|
renderWithProviders(<NationalHolidaysCard canUpdate year={1405} />);
|
|
|
|
await waitFor(() => expect(screen.getByText(/تعطیلی رسمی ثبت نشده است/)).toBeInTheDocument());
|
|
});
|
|
});
|