import { describe, it, expect, beforeEach, vi } from 'vitest'; import { screen, 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 InvoiceSummaryModal from './InvoiceSummaryModal'; const get = api.get as ReturnType; const baseInvoice = { uuid: 'iv1', status: 'finalized', issued_at: 1700000000, total_rials: 2_400_000, base_insurance_rials: 0, supplementary_rials: 0, patient_rials: 900_000, items: [{ uuid: 'it1', title: 'فول بادی', quantity: 1, total_rials: 2_400_000, patient_rials: 900_000 }], }; const fullSession = { session_at: 1700000000, paid_at: 1700100000, services_total_rials: 2_400_000, consumables_total_rials: 40_000, discount_rials: 200_000, final_price_rials: 2_240_000, paid_total_rials: 1_500_000, // API واقعی همیشه این را می‌فرستد: max(0, final − discount − paid) remaining_rials: 540_000, payments: [ { uuid: 'p1', method: 'wallet', amount_rials: 1_500_000, paid_at: 1700100000, created_by_name: 'منشی تست' }, ], consumables: [ { uuid: 'c1', item_name: 'عینک', quantity: 2, line_total_rials: 40_000 }, ], }; beforeEach(() => { get.mockReset(); }); function mockInvoice(invoice: object) { get.mockResolvedValue({ success: true, data: { data: invoice } }); } describe('InvoiceSummaryModal', () => { it('با session کامل: جدول کالای مصرفی، پرداختی‌ها و تخفیف را نشان می‌دهد', async () => { mockInvoice({ ...baseInvoice, session: fullSession }); renderWithProviders( {}} />); await waitFor(() => expect(screen.getByText('اطلاعات فاکتور')).toBeInTheDocument()); // کالای مصرفی expect(screen.getByText('اطلاعات کالای مصرفی')).toBeInTheDocument(); expect(screen.getByText('عینک')).toBeInTheDocument(); // پرداختی‌ها با label فارسی روش و ثبت‌کننده expect(screen.getByText('پرداختی ها')).toBeInTheDocument(); expect(screen.getByText('پرداخت از کیف پول')).toBeInTheDocument(); expect(screen.getByText('منشی تست')).toBeInTheDocument(); // خلاصه مالی با ستون تخفیف و جمع کالا expect(screen.getByText('تخفیف')).toBeInTheDocument(); expect(screen.getByText('جمع مبلغ کالا')).toBeInTheDocument(); // وضعیت — مبالغ واقعی (نمایش تومان = ریال ÷ ۱۰): // پرداخت‌شده ۱۵۰٬۰۰۰ (هم در جدول پرداختی‌ها هم وضعیت) و باقی‌مانده ۵۴٬۰۰۰ // (۲۲۴۰۰۰۰ − ۲۰۰۰۰۰ تخفیف − ۱۵۰۰۰۰۰ پرداختی = ۵۴۰۰۰۰ ریال؛ final_price پیش از تخفیف است) expect(screen.getAllByText(/۱۵۰٬۰۰۰/).length).toBeGreaterThanOrEqual(2); expect(screen.getByText(/۵۴٬۰۰۰/)).toBeInTheDocument(); }); it('بدون session (فاکتور قدیمی): رفتار قبلی حفظ می‌شود', async () => { mockInvoice({ ...baseInvoice, session: null }); renderWithProviders( {}} />); await waitFor(() => expect(screen.getByText('اطلاعات فاکتور')).toBeInTheDocument()); // جدول‌های session-محور رندر نمی‌شوند expect(screen.queryByText('اطلاعات کالای مصرفی')).not.toBeInTheDocument(); expect(screen.queryByText('پرداختی ها')).not.toBeInTheDocument(); // خلاصه مالی قدیمی با سهم بیمار expect(screen.getByText('سهم بیمار')).toBeInTheDocument(); }); it('session با payments/consumables خالی: ردیف خط تیره', async () => { mockInvoice({ ...baseInvoice, session: { ...fullSession, payments: [], consumables: [], paid_total_rials: 0, discount_rials: 0 }, }); renderWithProviders( {}} />); await waitFor(() => expect(screen.getByText('اطلاعات فاکتور')).toBeInTheDocument()); expect(screen.getByText('اطلاعات کالای مصرفی')).toBeInTheDocument(); expect(screen.getByText('پرداختی ها')).toBeInTheDocument(); // ردیف‌های '-' برای هر دو جدول خالی + ستون تخفیف صفر expect(screen.getAllByText('-').length).toBeGreaterThanOrEqual(8); }); it('invoiceUuid=null: مودال بسته و بدون fetch', () => { renderWithProviders( {}} />); expect(get).not.toHaveBeenCalled(); expect(screen.queryByText('خلاصه فاکتور')).not.toBeInTheDocument(); }); it('فاکتور بیمه‌ای: نوع خدمت، نام بیمه و سهم‌ها درج می‌شوند', async () => { mockInvoice({ ...baseInvoice, base_insurance_rials: 1_785_600, patient_rials: 4_166_400, total_rials: 5_952_000, service_category: 'inpatient', service_category_label: 'خدمات بستری', base_insurance_name: 'بیمه ایران', items: [{ uuid: 'it1', title: 'ویزیت', quantity: 1, total_rials: 5_952_000, patient_rials: 4_166_400 }], }); renderWithProviders( {}} />); await waitFor(() => expect(screen.getByText('اطلاعات بیمه')).toBeInTheDocument()); expect(screen.getByText('نوع خدمت بیمه')).toBeInTheDocument(); expect(screen.getByText('خدمات بستری')).toBeInTheDocument(); expect(screen.getByText('بیمه ایران')).toBeInTheDocument(); }); it('فاکتور بدون بیمه، جدول بیمه ندارد', async () => { mockInvoice(baseInvoice); renderWithProviders( {}} />); await waitFor(() => expect(screen.getByText('اطلاعات فاکتور')).toBeInTheDocument()); expect(screen.queryByText('اطلاعات بیمه')).not.toBeInTheDocument(); }); });