Files
clinicpro/assets/admin/pages/StaffSessionDetailPage.test.tsx
T
hamedandClaude Opus 5 cc2e630c40 refactor(admin): stop asking the operator to re-pick the session's device
The appointment is booked on a device, and SessionExecutor already stamps that
device onto every area record when the session starts. The area form still
showed a device select — pre-filled, but a select — so the operator was asked
to make a decision that had already been made at booking time.

The inherited device is now read-only text. A "تغییر" button reveals the
select, for the one case that still needs it: the appointment was booked on the
wrong device. An appointment with no resource at all still gets the select
outright, with a hint saying why.

Also in this file: the parameter fields wrapped a label and a SearchableSelect
inside `.field`, which is itself the bordered input box — two nested boxes. They
are `.field-block` now, each control labelled by id. The note textarea gets
`cp-textarea`; it had no styling at all. Session and area counts go through
formatNumber, so the page no longer mixes Latin and Persian digits.

Adds the test file the page never had.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:00:29 +03:30

108 lines
3.8 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { screen, fireEvent } 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('react-router-dom', async () => {
const actual = await vi.importActual<typeof import('react-router-dom')>('react-router-dom');
return { ...actual, useParams: () => ({ uuid: 'ses-1' }) };
});
import { api } from '../lib/api';
import StaffSessionDetailPage from './StaffSessionDetailPage';
const get = api.get as ReturnType<typeof vi.fn>;
const DEVICE = { uuid: 'res-1', name: 'کندلا ۲۰۲۳', type: 'laser' };
const OTHER = { uuid: 'res-2', name: 'دستگاه دیگر', type: 'laser' };
function detail(areaResource: typeof DEVICE | null) {
return {
uuid: 'ses-1',
session_number: 1,
total_sessions: 3,
status: 'in_progress',
due_at: null,
started_at: 1_786_000_000,
finished_at: null,
note: null,
performed_by: null,
appointment: null,
case: {
uuid: 'case-1',
status: 'active',
total_sessions: 3,
completed_sessions: 0,
opened_at: 1_786_000_000,
closed_at: null,
service: { uuid: 'svc-1', name: 'لیزر توتال' },
supervisor: null,
areas: [],
},
devices: [
{ uuid: DEVICE.uuid, name: DEVICE.name },
{ uuid: OTHER.uuid, name: OTHER.name },
],
forms: { 'res-1': [] },
areas: [{
uuid: 'area-1',
area: { uuid: 'ca-1', name: 'صورت' },
status: 'pending',
parameters: null,
started_at: null,
finished_at: null,
note: null,
resource: areaResource,
}],
};
}
beforeEach(() => {
get.mockReset();
});
describe('صفحهٔ انجام جلسه — دستگاه ناحیه', () => {
/**
* دستگاه هنگام ثبت نوبت انتخاب شده و روی رکورد ناحیه نشسته؛ اپراتور نباید همان
* تصمیم را دوباره بگیرد.
*/
it('دستگاهِ به‌ارث‌رسیده را فقط نشان می‌دهد، انتخاب نمی‌خواهد', async () => {
get.mockResolvedValue({ success: true, data: detail(DEVICE) });
renderWithProviders(<StaffSessionDetailPage />);
fireEvent.click(await screen.findByRole('button', { name: 'ثبت اطلاعات این ناحیه' }));
expect(screen.getByText(/از نوبت این جلسه آمده/)).toBeInTheDocument();
expect(screen.queryByLabelText('دستگاه ناحیهٔ صورت')).not.toBeInTheDocument();
});
/** موردِ نادرِ «نوبت روی دستگاه اشتباه» نباید بن‌بست شود. */
it('با «تغییر» انتخابگر ظاهر می‌شود', async () => {
get.mockResolvedValue({ success: true, data: detail(DEVICE) });
renderWithProviders(<StaffSessionDetailPage />);
fireEvent.click(await screen.findByRole('button', { name: 'ثبت اطلاعات این ناحیه' }));
fireEvent.click(screen.getByRole('button', { name: 'تغییر' }));
expect(screen.getByLabelText('دستگاه ناحیهٔ صورت')).toBeInTheDocument();
});
/** نوبتِ بدون منبع هنوز باید راهی برای انتخاب داشته باشد. */
it('اگر نوبت روی دستگاهی نبوده، انتخابگر را می‌آورد', async () => {
get.mockResolvedValue({ success: true, data: detail(null) });
renderWithProviders(<StaffSessionDetailPage />);
fireEvent.click(await screen.findByRole('button', { name: 'ثبت اطلاعات این ناحیه' }));
expect(screen.getByLabelText('دستگاه ناحیهٔ صورت')).toBeInTheDocument();
expect(screen.getByText(/روی دستگاهی ثبت نشده/)).toBeInTheDocument();
});
});