feat(patient): implement record number pattern management
- Add RecordNumberSettingsController for managing patient record number patterns. - Create RecordNumberPattern entity to represent the pattern configuration. - Implement RecordNumberPatternRepository for database interactions. - Develop RecordNumberGenerator service for generating and validating record numbers. - Add tests for record number generation, backfilling, and API interactions. - Ensure proper access control for viewing and updating patterns based on user roles.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { screen, fireEvent, 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 {},
|
||||
}));
|
||||
|
||||
import { api } from '../lib/api';
|
||||
import PatientRecordFormPage from './PatientRecordFormPage';
|
||||
|
||||
const get = api.get as ReturnType<typeof vi.fn>;
|
||||
const post = api.post as ReturnType<typeof vi.fn>;
|
||||
|
||||
/** الگوی شمارهٔ پرونده؛ `enabled=false` یعنی رفتار قدیمیِ ورود دستی. */
|
||||
function mockPattern(settings: Record<string, unknown>) {
|
||||
get.mockImplementation((url: string) =>
|
||||
url.includes('patient-record-number-settings')
|
||||
? Promise.resolve({ success: true, data: { pattern: '{YY}-{SEQ:4}', reset_policy: 'none', counter: 0, next_preview: '05-0001', ...settings } })
|
||||
: Promise.resolve({ success: true, data: [] }),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* پرکردن فیلدهای الزامیِ دیگر تا فقط شمارهٔ پرونده متغیر بماند.
|
||||
*
|
||||
* اول منتظر رسیدن تنظیمات میماند: رندرِ بعد از پاسخ، منوی باز react-select را
|
||||
* میبندد و انتخاب جنسیت را میخورد.
|
||||
*/
|
||||
async function fillRequiredFields() {
|
||||
await waitFor(() => expect(get).toHaveBeenCalledWith(expect.stringContaining('patient-record-number-settings')));
|
||||
await waitFor(() => expect(screen.getByRole('button', { name: /ثبت|ذخیره/ })).toBeEnabled());
|
||||
|
||||
fireEvent.change(await screen.findByPlaceholderText('نام و نام خانوادگی را وارد نمایید'), { target: { value: 'علی محمدی' } });
|
||||
fireEvent.change(screen.getByPlaceholderText('کد ملی را وارد نمایید'), { target: { value: '0012345675' } });
|
||||
fireEvent.change(screen.getByPlaceholderText('شماره تماس را وارد نمایید'), { target: { value: '09121234567' } });
|
||||
const gender = document.getElementById('patient-gender-select') as HTMLInputElement;
|
||||
fireEvent.focus(gender);
|
||||
fireEvent.keyDown(gender, { key: 'ArrowDown' });
|
||||
fireEvent.click(await screen.findByText('مرد'));
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
get.mockReset();
|
||||
post.mockReset();
|
||||
post.mockResolvedValue({ success: true, data: { uuid: 'rec-new' } });
|
||||
(api.patch as ReturnType<typeof vi.fn>).mockResolvedValue({ success: true, data: {} });
|
||||
});
|
||||
|
||||
describe('PatientRecordFormPage — شمارهٔ پرونده', () => {
|
||||
/** ⚠️ مرزی: بدون الگو، فیلد الزامی میماند (رفتار امروز). */
|
||||
it('بدون الگو شماره پرونده الزامی است', async () => {
|
||||
mockPattern({ enabled: false, can_edit: true });
|
||||
renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });
|
||||
|
||||
await fillRequiredFields();
|
||||
fireEvent.click(screen.getByText('ثبت اطلاعات') ?? screen.getByRole('button', { name: /ثبت|ذخیره/ }));
|
||||
|
||||
expect(await screen.findByText('شماره پرونده الزامی است')).toBeInTheDocument();
|
||||
expect(post).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
/** ✅ موفق: با الگوی فعال و بدون اجازهٔ دستی، فیلد read-only است و ارسال نمیشود. */
|
||||
it('با الگوی فعال و بدون can_edit، شماره فرستاده نمیشود', async () => {
|
||||
mockPattern({ enabled: true, can_edit: false });
|
||||
renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });
|
||||
|
||||
expect(await screen.findByText('شماره از الگوی مجموعه ساخته میشود')).toBeInTheDocument();
|
||||
|
||||
await fillRequiredFields();
|
||||
fireEvent.click(screen.getByRole('button', { name: /ثبت|ذخیره/ }));
|
||||
|
||||
await waitFor(() => expect(post).toHaveBeenCalled());
|
||||
expect(post.mock.calls[0][1]).not.toHaveProperty('record_number');
|
||||
});
|
||||
|
||||
/** ✅ موفق: صاحب مجموعه میتواند خالی بگذارد تا سرور بسازد. */
|
||||
it('صاحب مجموعه میتواند شماره را خالی بگذارد', async () => {
|
||||
mockPattern({ enabled: true, can_edit: true });
|
||||
renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });
|
||||
|
||||
expect(await screen.findByText(/خالی بماند تا از الگو ساخته شود/)).toBeInTheDocument();
|
||||
|
||||
await fillRequiredFields();
|
||||
fireEvent.click(screen.getByRole('button', { name: /ثبت|ذخیره/ }));
|
||||
|
||||
await waitFor(() => expect(post).toHaveBeenCalled());
|
||||
expect(post.mock.calls[0][1].record_number).toBe('');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user