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 {}, })); vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } })); import { api } from '../lib/api'; import AppointmentInvoiceCard from './AppointmentInvoiceCard'; const get = api.get as ReturnType; const invoice = { base_rials: 10_000_000, items_rials: 2_000_000, discount_rials: 1_200_000, insurance_base_rials: 2_160_000, insurance_supplementary_rials: 0, tax_rials: 432_000, final_rials: 9_072_000, deposit_rials: 1_425_600, created_at: 1_700_000_000, breakdown: { discounts: [{ label: 'تخفیف درصدی', rials: 1_200_000 }], sources: {} }, }; describe('AppointmentInvoiceCard', () => { beforeEach(() => vi.clearAllMocks()); it('lays out the chain down to the final amount', async () => { get.mockResolvedValue({ success: true, data: invoice }); renderWithProviders(, { route: '/admin/appointments/a1' }); await waitFor(() => expect(screen.getByText('فاکتور')).toBeInTheDocument()); expect(screen.getByText('قیمت پایه')).toBeInTheDocument(); expect(screen.getByText('مبلغ نهایی')).toBeInTheDocument(); expect(screen.getByText('بیعانه')).toBeInTheDocument(); }); /** ردیف صفر نباید جا بگیرد — فاکتور شلوغ خوانده نمی‌شود. */ it('hides zero rows', async () => { get.mockResolvedValue({ success: true, data: invoice }); renderWithProviders(, { route: '/admin/appointments/a1' }); await waitFor(() => expect(screen.getByText('فاکتور')).toBeInTheDocument()); expect(screen.queryByText('سهم بیمهٔ تکمیلی')).not.toBeInTheDocument(); }); /** ⭐ نبودِ فاکتور خطا نیست: نوبتِ ثبت‌نهایی‌نشده فاکتوری ندارد. */ it('treats a missing invoice as a normal state', async () => { get.mockRejectedValue(new Error('not found')); renderWithProviders(, { route: '/admin/appointments/a1' }); await waitFor(() => expect(screen.getByText('برای این نوبت فاکتوری ثبت نشده است.')).toBeInTheDocument(), ); }); it('says the snapshot does not follow later price changes', async () => { get.mockResolvedValue({ success: true, data: invoice }); renderWithProviders(, { route: '/admin/appointments/a1' }); await waitFor(() => expect(screen.getByText(/تغییر بعدی تعرفه این فاکتور را عوض نمی‌کند/)).toBeInTheDocument(), ); }); });