Files
clinicpro/assets/admin/pages/PatientRecordFormPage.test.tsx
T
hamedandClaude Opus 4.8 15c6f5dce7 feat(patients): phase A — records list + create/edit form (Figma)
Rebuild the patient records (پرونده‌ها) area, phase A of the Figma redesign:

- BE: add a clinic-scoped `record_number` and a TenantTag `tags` M2M to
  PatientRecord (migration + EAGER-hydrated collection). POST /patient and
  PATCH /patient/{uuid} now accept `record_number` and tenant-scoped `tags`
  (foreign tag → 422); demographic fields (gender, date_of_birth,
  referral_source, description) continue to live on UserProfile via PATCH.
- FE: new PatientsListPage (table + card views, search, pagination, tags
  column, "تشکیل پرونده") at /admin/patients, and PatientRecordFormPage
  (create/edit) that POSTs the record then PATCHes the demographics. Point
  the sidebar "پرونده" entry to the new list.

Phases B–E (tabbed patient file, service stepper, invoice, payments/wallet,
call-center) follow. Backend covered by PHPUnit, FE by Vitest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:54:38 +03:30

54 lines
3.1 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { screen, fireEvent, waitFor } from '@testing-library/react';
import { renderWithProviders } from '../test/utils';
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
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 post = api.post as ReturnType<typeof vi.fn>;
const patch = api.patch as ReturnType<typeof vi.fn>;
beforeEach(() => {
post.mockReset(); patch.mockReset();
post.mockResolvedValue({ success: true, data: { uuid: 'new-1' } });
patch.mockResolvedValue({ success: true, data: {} });
});
describe('PatientRecordFormPage (تشکیل پرونده)', () => {
it('creates a record then patches the demographic fields', async () => {
renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });
fireEvent.change(screen.getByPlaceholderText('نام و نام خانوادگی را وارد نمایید'), { target: { value: 'بیمار نمونه' } });
fireEvent.change(screen.getByPlaceholderText('شماره پرونده'), { target: { value: 'P-1001' } });
fireEvent.change(screen.getAllByRole('combobox')[0], { target: { value: 'female' } }); // gender
fireEvent.change(screen.getByPlaceholderText('کد ملی را وارد نمایید'), { target: { value: '1234567890' } });
fireEvent.change(screen.getByPlaceholderText('شماره تماس را وارد نمایید'), { target: { value: '09120000000' } });
fireEvent.click(screen.getByRole('button', { name: 'ثبت اطلاعات' }));
await waitFor(() => expect(post).toHaveBeenCalledWith('/api/v1/patient', expect.objectContaining({
name: 'بیمار نمونه', mobile: '09120000000', national_code: '1234567890', record_number: 'P-1001',
})));
await waitFor(() => expect(patch).toHaveBeenCalledWith('/api/v1/patient/new-1', expect.objectContaining({ gender: 'female' })));
});
it('blocks submit and shows a validation error for a bad national code', async () => {
renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });
fireEvent.change(screen.getByPlaceholderText('نام و نام خانوادگی را وارد نمایید'), { target: { value: 'ب' } });
fireEvent.change(screen.getByPlaceholderText('شماره پرونده'), { target: { value: 'P-1' } });
fireEvent.change(screen.getAllByRole('combobox')[0], { target: { value: 'male' } });
fireEvent.change(screen.getByPlaceholderText('کد ملی را وارد نمایید'), { target: { value: '12' } });
fireEvent.change(screen.getByPlaceholderText('شماره تماس را وارد نمایید'), { target: { value: '09120000000' } });
fireEvent.click(screen.getByRole('button', { name: 'ثبت اطلاعات' }));
expect(await screen.findByText('کد ملی باید ۱۰ رقم باشد')).toBeInTheDocument();
expect(post).not.toHaveBeenCalled();
});
});