import { describe, it, expect, beforeEach, vi } from 'vitest'; import { screen, fireEvent, 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 CreateStep from './CreateStep'; const get = api.get as ReturnType; const post = api.post as ReturnType; function mockEndpoints(pricing: { free_visit_price_rials: number; require_visit_price: boolean }) { get.mockImplementation((url: string) => { if (url === '/api/v1/insurance-pricing') return Promise.resolve({ success: true, data: pricing }); if (url === '/api/v1/inventory-items') return Promise.resolve({ success: true, data: { items: [] } }); if (url === '/api/v1/billing/tenant-insurances') return Promise.resolve({ success: true, data: { data: [] } }); return Promise.resolve({ success: true, data: [] }); }); } beforeEach(() => { get.mockReset(); post.mockReset(); post.mockResolvedValue({ success: true, data: { uuid: 's-1' } }); }); const renderStep = (onCreated = vi.fn()) => { renderWithProviders( {}} />, ); return onCreated; }; describe('CreateStep — الزامی بودن قیمت ویزیت با فلگ require_visit_price', () => { it('فلگ فعال + قیمت صفر → خطای inline، ستاره روی label و عدم ارسال', async () => { mockEndpoints({ free_visit_price_rials: 0, require_visit_price: true }); renderStep(); await waitFor(() => expect(screen.getByText(/قیمت ویزیت \(تومان\)/)).toBeInTheDocument()); await waitFor(() => expect(screen.getByText('*')).toBeInTheDocument()); fireEvent.click(screen.getByText('ایجاد سرویس')); expect(await screen.findByText('هزینه ویزیت الزامی است')).toBeInTheDocument(); expect(post).not.toHaveBeenCalled(); }); it('فلگ فعال + مقدار معتبر → POST با visit_price_rials ریالی', async () => { mockEndpoints({ free_visit_price_rials: 0, require_visit_price: true }); renderStep(); await waitFor(() => expect(screen.getByText('*')).toBeInTheDocument()); fireEvent.change(screen.getByLabelText('قیمت ویزیت'), { target: { value: '50000' } }); fireEvent.click(screen.getByText('ایجاد سرویس')); await waitFor(() => expect(post).toHaveBeenCalled()); expect(post.mock.calls[0][0]).toBe('/api/v1/patient/r-1/session'); expect(post.mock.calls[0][1]).toMatchObject({ visit_price_rials: 500_000 }); }); it('فلگ غیرفعال + قیمت صفر → رفتار قبلی: ثبت مجاز', async () => { mockEndpoints({ free_visit_price_rials: 0, require_visit_price: false }); const onCreated = renderStep(); await waitFor(() => expect(get).toHaveBeenCalledWith('/api/v1/insurance-pricing')); fireEvent.click(screen.getByText('ایجاد سرویس')); await waitFor(() => expect(post).toHaveBeenCalled()); expect(post.mock.calls[0][1]).toMatchObject({ visit_price_rials: 0 }); await waitFor(() => expect(onCreated).toHaveBeenCalledWith('s-1')); expect(screen.queryByText('هزینه ویزیت الزامی است')).not.toBeInTheDocument(); }); it('پیش‌فرض قیمت از «قیمت ویزیت آزاد» پر می‌شود (ریال → تومان)', async () => { mockEndpoints({ free_visit_price_rials: 300_000, require_visit_price: false }); renderStep(); await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue('30000')); }); });