- 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.
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', 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();
|
|
});
|
|
});
|