Files
clinicpro/assets/admin/pages/StaffSessionDetailPage.test.tsx
T
hamed 6876135a53 feat: add BlogBodySanitizer for HTML sanitization on article save
- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks.
- Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content.
- Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
2026-08-07 21:13:38 +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', async () => {
const actual = await vi.importActual<typeof import('react-router')>('react-router');
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();
});
});