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 { toast } from 'sonner'; import DetailsStep from './DetailsStep'; import type { SessionCardData } from '../SessionServiceCard'; const post = api.post as ReturnType; const session: SessionCardData = { uuid: 's1', services: [{ service_name: 'لیزر' }], doctor_name: 'دکتر فتحی', final_price_rials: 1_000_000, patient_debt_rials: 0, discount_rials: 0, visit_price_rials: 0, payments: [], }; beforeEach(() => { post.mockReset(); (toast.error as ReturnType).mockReset(); }); describe('DetailsStep — صدور فاکتور', () => { it('فاکتور را می‌سازد، draft را finalize می‌کند و بعد onFinish', async () => { post.mockImplementation((url: string) => url === '/api/v1/billing/invoices' ? Promise.resolve({ success: true, data: { data: { uuid: 'iv1', status: 'draft' } } }) : Promise.resolve({ success: true, data: {} }), ); const onFinish = vi.fn(); renderWithProviders( {}} onFinish={onFinish} />); fireEvent.click(screen.getByText('صدور فاکتور')); await waitFor(() => expect(onFinish).toHaveBeenCalled()); expect(post).toHaveBeenCalledWith('/api/v1/billing/invoices', { session_uuid: 's1' }); expect(post).toHaveBeenCalledWith('/api/v1/billing/invoices/iv1/finalize', {}); }); it('فاکتور غیر draft (idempotent create) دیگر finalize نمی‌شود', async () => { post.mockResolvedValue({ success: true, data: { data: { uuid: 'iv1', status: 'finalized' } } }); const onFinish = vi.fn(); renderWithProviders( {}} onFinish={onFinish} />); fireEvent.click(screen.getByText('صدور فاکتور')); await waitFor(() => expect(onFinish).toHaveBeenCalled()); expect(post).toHaveBeenCalledTimes(1); }); it('session با invoice_uuid موجود: بدون درخواست، مستقیم onFinish', async () => { const onFinish = vi.fn(); renderWithProviders( {}} onFinish={onFinish} />, ); fireEvent.click(screen.getByText('صدور فاکتور')); await waitFor(() => expect(onFinish).toHaveBeenCalled()); expect(post).not.toHaveBeenCalled(); }); it('خطای صدور: toast خطا و onFinish صدا زده نمی‌شود', async () => { post.mockRejectedValue(new Error('boom')); const onFinish = vi.fn(); renderWithProviders( {}} onFinish={onFinish} />); fireEvent.click(screen.getByText('صدور فاکتور')); await waitFor(() => expect(toast.error).toHaveBeenCalledWith('صدور فاکتور ناموفق بود')); expect(onFinish).not.toHaveBeenCalled(); }); });