- Changed franchise_rials to franchise_percent in tenant_insurances and tenant_service_coverage tables. - Reset old rial values to 0/NULL as they are not convertible to percentage. feat(command): add SeedInsuranceScenarioCommand for seeding insurance data - Implemented a command to seed supplementary insurance contracts, patients, and claims for a specified doctor. - Includes functionality for purging existing scenario data and generating new entries with predefined contracts and patient scenarios.
184 lines
8.3 KiB
TypeScript
184 lines
8.3 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { screen, fireEvent } from '@testing-library/react';
|
|
import { renderWithProviders } from '../test/utils';
|
|
import InsuranceModal, {
|
|
buildInsurancePayload, contractToForm, EMPTY_FORM, type Contract, type InsuranceOption,
|
|
} from './InsuranceModal';
|
|
import type { ServiceCategoryOption } from '../hooks/useServiceCategories';
|
|
|
|
const mkContract = (over: Partial<Contract> = {}): Contract => ({
|
|
uuid: 'c-1', insurance_id: 3, insurance_name: 'بیمه ایران', insurance_kind: 'basic',
|
|
version: 1, is_active: true, coverage_percent: 70, franchise_percent: 15,
|
|
annual_ceiling_rials: 20_000_000, kind: 'basic', effective_from: 1_700_000_000,
|
|
effective_to: null,
|
|
category_coverages: { outpatient: 70, inpatient: 30 },
|
|
category_coverage_source: { outpatient: 'override', inpatient: 'admin_default' },
|
|
...over,
|
|
});
|
|
|
|
const options: InsuranceOption[] = [
|
|
{ insurance_id: 3, insurance_name: 'بیمه ایران', type: 'basic', coverage_defaults: { outpatient: 70, inpatient: 30 } },
|
|
{ insurance_id: 5, insurance_name: 'بیمه آسیا', type: 'supplementary', coverage_defaults: { outpatient: 40, inpatient: 20 } },
|
|
];
|
|
|
|
const categories: ServiceCategoryOption[] = [
|
|
{ key: 'outpatient', label: 'خدمات سرپایی' },
|
|
{ key: 'inpatient', label: 'خدمات بستری' },
|
|
];
|
|
|
|
describe('buildInsurancePayload', () => {
|
|
it('keeps the franchise a percent, converts ceiling toman → rials and Y-m-d → unix', () => {
|
|
const payload = buildInsurancePayload({
|
|
...EMPTY_FORM, insuranceId: '3', kind: 'supplementary',
|
|
categoryPercents: { outpatient: '80', inpatient: '30' },
|
|
franchise: '10', ceiling: '2000000',
|
|
effectiveFrom: '2024-01-01', effectiveTo: '2025-01-01',
|
|
});
|
|
expect(payload.insurance_id).toBe(3);
|
|
expect(payload.kind).toBe('supplementary');
|
|
expect(payload.coverage_percent).toBe(80); // ستون قدیمی = درصد سرپایی
|
|
expect(payload.category_coverages).toEqual([
|
|
{ key: 'outpatient', coverage_percent: 80 },
|
|
{ key: 'inpatient', coverage_percent: 30 },
|
|
]);
|
|
expect(payload.franchise_percent).toBe(10); // درصد است، نه مبلغ
|
|
expect(payload.annual_ceiling_rials).toBe(20_000_000);
|
|
expect(typeof payload.effective_from).toBe('number');
|
|
expect(payload.effective_to).toBeGreaterThan(payload.effective_from!);
|
|
});
|
|
|
|
it('empty ceiling → null (بینهایت), empty dates → null', () => {
|
|
const payload = buildInsurancePayload({
|
|
...EMPTY_FORM, insuranceId: '3', categoryPercents: { outpatient: '50' },
|
|
});
|
|
expect(payload.annual_ceiling_rials).toBeNull();
|
|
expect(payload.effective_from).toBeNull();
|
|
expect(payload.effective_to).toBeNull();
|
|
});
|
|
|
|
it('forces franchise to zero on a basic contract', () => {
|
|
const payload = buildInsurancePayload({
|
|
...EMPTY_FORM, insuranceId: '3', kind: 'basic', franchise: '10',
|
|
categoryPercents: { outpatient: '70' },
|
|
});
|
|
expect(payload.franchise_percent).toBe(0);
|
|
});
|
|
|
|
it('omits category_coverages when the user may not override them', () => {
|
|
const payload = buildInsurancePayload(
|
|
{ ...EMPTY_FORM, insuranceId: '3', categoryPercents: { outpatient: '70' } },
|
|
null,
|
|
false,
|
|
);
|
|
expect(payload).not.toHaveProperty('category_coverages');
|
|
});
|
|
});
|
|
|
|
describe('contractToForm', () => {
|
|
it('maps the franchise percent, contract kind, and effective category percents', () => {
|
|
const form = contractToForm(mkContract({ franchise_percent: 30, kind: 'supplementary' }));
|
|
expect(form.franchise).toBe('30');
|
|
expect(form.kind).toBe('supplementary');
|
|
expect(form.categoryPercents).toEqual({ outpatient: '70', inpatient: '30' });
|
|
});
|
|
});
|
|
|
|
describe('InsuranceModal', () => {
|
|
it('renders one percent input per category and hides franchise on basic', () => {
|
|
renderWithProviders(
|
|
<InsuranceModal open editContract={null} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={() => {}} />,
|
|
);
|
|
expect(screen.getByText('افزودن بیمه')).toBeInTheDocument();
|
|
expect(screen.getByText('نام بیمه')).toBeInTheDocument();
|
|
// Manual "نوع بیمه" select is gone; kind is shown as a read-only chip from the tab.
|
|
expect(screen.queryByText('نوع بیمه')).not.toBeInTheDocument();
|
|
expect(screen.getByText('پایه')).toBeInTheDocument();
|
|
expect(screen.getByText('درصد پوشش — خدمات سرپایی')).toBeInTheDocument();
|
|
expect(screen.getByText('درصد پوشش — خدمات بستری')).toBeInTheDocument();
|
|
expect(screen.queryByText('فرانشیز (درصد)')).not.toBeInTheDocument();
|
|
expect(screen.getByText('سقف تعهد (تومان)')).toBeInTheDocument();
|
|
expect(screen.getByText('ثبت بیمه')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows the franchise field for a supplementary contract', () => {
|
|
renderWithProviders(
|
|
<InsuranceModal open editContract={null} options={options} categories={categories} kind="supplementary" onClose={() => {}} onSubmit={() => {}} />,
|
|
);
|
|
expect(screen.getByText('تکمیلی')).toBeInTheDocument();
|
|
expect(screen.getByText('فرانشیز (درصد)')).toBeInTheDocument();
|
|
});
|
|
|
|
it('blocks submit until every rendered category has a valid percent', () => {
|
|
const onSubmit = vi.fn();
|
|
renderWithProviders(
|
|
<InsuranceModal
|
|
open
|
|
editContract={mkContract({ category_coverages: { outpatient: 70 } })}
|
|
options={options}
|
|
categories={categories}
|
|
kind="basic"
|
|
onClose={() => {}}
|
|
onSubmit={onSubmit}
|
|
/>,
|
|
);
|
|
|
|
// بستری بدون درصد مانده: ثبت باید بسته باشد و پیام الزامی دیده شود.
|
|
expect(screen.getByText('ثبت بیمه')).toBeDisabled();
|
|
expect(screen.getByText('درصد پوشش الزامی است (۱ تا ۱۰۰)')).toBeInTheDocument();
|
|
|
|
fireEvent.change(screen.getByLabelText('درصد پوشش خدمات بستری'), { target: { value: '30' } });
|
|
expect(screen.getByText('ثبت بیمه')).not.toBeDisabled();
|
|
|
|
fireEvent.click(screen.getByText('ثبت بیمه'));
|
|
expect(onSubmit).toHaveBeenCalled();
|
|
});
|
|
|
|
it('renders only the service kinds it is given', () => {
|
|
renderWithProviders(
|
|
<InsuranceModal
|
|
open
|
|
editContract={null}
|
|
options={options}
|
|
categories={[{ key: 'outpatient', label: 'خدمات سرپایی' }]}
|
|
kind="basic"
|
|
onClose={() => {}}
|
|
onSubmit={() => {}}
|
|
/>,
|
|
);
|
|
expect(screen.getByText('درصد پوشش — خدمات سرپایی')).toBeInTheDocument();
|
|
expect(screen.queryByText('درصد پوشش — خدمات بستری')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('prefills the percents of an edited contract and marks admin defaults', () => {
|
|
renderWithProviders(
|
|
<InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={() => {}} />,
|
|
);
|
|
expect(screen.getByLabelText('درصد پوشش خدمات سرپایی')).toHaveValue('70');
|
|
expect(screen.getByLabelText('درصد پوشش خدمات بستری')).toHaveValue('30');
|
|
expect(screen.getByText('پیشفرض ادمین')).toBeInTheDocument();
|
|
});
|
|
|
|
it('makes the percents read-only without the update permission', () => {
|
|
renderWithProviders(
|
|
<InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" canUpdate={false} onClose={() => {}} onSubmit={() => {}} />,
|
|
);
|
|
expect(screen.getByLabelText('درصد پوشش خدمات سرپایی')).toHaveAttribute('readonly');
|
|
expect(screen.getAllByText('مقدار پیشفرض تنظیمات مرکزی').length).toBe(2);
|
|
});
|
|
|
|
it('submits the built payload for an edited contract', () => {
|
|
const onSubmit = vi.fn();
|
|
renderWithProviders(
|
|
<InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={onSubmit} />,
|
|
);
|
|
fireEvent.click(screen.getByText('ثبت بیمه'));
|
|
expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
|
insurance_id: 3, coverage_percent: 70, franchise_percent: 0, kind: 'basic',
|
|
category_coverages: [
|
|
{ key: 'outpatient', coverage_percent: 70 },
|
|
{ key: 'inpatient', coverage_percent: 30 },
|
|
],
|
|
}));
|
|
});
|
|
});
|