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>
108 lines
3.8 KiB
TypeScript
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();
|
|
});
|
|
});
|