Screenshotting the pages under dark mode and compact density (rather than trusting that design tokens were enough) turned up two mistakes repeated across every page this feature set added: - `.card` carries only the surface, border and radius — padding comes from the separate `.card-pad`. Fifteen cards were rendering with their content flush against the edges. - `.field` *is* the input box, a 40px-tall flex row. Wrapping a label plus a control in it produced a joined addon rather than a label above its field. `.field-block` is the label-above layout, and thirty-seven wrappers now use it. Both were invisible to type-checking and to the tests, which is exactly why the visual pass was worth running. Numbers in the new UI now go through formatNumber so they render as Persian digits, and the utilization page's header no longer repeats the sentence that appears under its filters verbatim. The QA driver gained a `--ui` flag: theme and density live in localStorage['clinicpro-ui'], so without seeding them dark mode and compact density cannot be screenshotted at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { screen, waitFor } from '@testing-library/react';
|
|
import { renderWithProviders } from '../test/utils';
|
|
|
|
vi.mock('../lib/api', () => ({
|
|
api: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn() },
|
|
ApiError: class extends Error {},
|
|
}));
|
|
|
|
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
|
|
|
|
import { api } from '../lib/api';
|
|
import AppointmentSegmentsCard from './AppointmentSegmentsCard';
|
|
|
|
const get = api.get as ReturnType<typeof vi.fn>;
|
|
|
|
const segment = (over: Record<string, unknown>) => ({
|
|
sequence: 1,
|
|
name: 'ویزیت',
|
|
starts_at: 1_800_000_000,
|
|
ends_at: 1_800_001_200,
|
|
duration_minutes: 20,
|
|
patient_present: true,
|
|
...over,
|
|
});
|
|
|
|
describe('AppointmentSegmentsCard', () => {
|
|
beforeEach(() => vi.clearAllMocks());
|
|
|
|
it('sums the recorded segments rather than the service duration', async () => {
|
|
get.mockResolvedValue({
|
|
data: [
|
|
segment({ sequence: 1, duration_minutes: 20 }),
|
|
segment({ sequence: 2, name: 'انتظار', duration_minutes: 40, patient_present: false }),
|
|
],
|
|
});
|
|
|
|
renderWithProviders(<AppointmentSegmentsCard appointmentUuid="a-1" />);
|
|
|
|
// ارقام فارسیاند: ۲۰ + ۴۰ = ۶۰
|
|
await waitFor(() => expect(screen.getByText('۶۰ دقیقه')).toBeInTheDocument());
|
|
});
|
|
|
|
/** ⭐ مدتی که بیمار روی صندلی نیست باید دیده شود، وگرنه «۹۰ دقیقه» گمراهکننده است. */
|
|
it('marks the segments the patient is not present for', async () => {
|
|
get.mockResolvedValue({
|
|
data: [segment({ sequence: 1, name: 'انتظار', patient_present: false })],
|
|
});
|
|
|
|
renderWithProviders(<AppointmentSegmentsCard appointmentUuid="a-1" />);
|
|
|
|
await waitFor(() => expect(screen.getByText('بدون حضور بیمار')).toBeInTheDocument());
|
|
});
|
|
|
|
/** نوبت اسلاتی بخشی ندارد؛ کارتِ خالی یعنی «چیزی خراب است». */
|
|
it('renders nothing for an appointment with no segments', async () => {
|
|
get.mockResolvedValue({ data: [] });
|
|
|
|
const { container } = renderWithProviders(<AppointmentSegmentsCard appointmentUuid="a-1" />);
|
|
|
|
await waitFor(() => expect(get).toHaveBeenCalled());
|
|
expect(container.textContent).toBe('');
|
|
});
|
|
});
|