Add tests and implementation for ServiceDetailPage and PriceInput components
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior. - Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities. - Add API tests for service item detail retrieval and coverage synchronization with insurance contracts. - Ensure proper error handling and user feedback for service item retrieval and coverage management.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { screen, fireEvent } from '@testing-library/react';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
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 { useAuthStore } from '../stores/authStore';
|
||||
import ServiceDetailPage from './ServiceDetailPage';
|
||||
|
||||
const get = api.get as ReturnType<typeof vi.fn>;
|
||||
|
||||
const ITEM = {
|
||||
uuid: 'it1',
|
||||
name: 'سرم ۵۰۰cc',
|
||||
section_uuid: 'sec1',
|
||||
section_name: 'تزریقات',
|
||||
price_rials: 8_500_000,
|
||||
active: true,
|
||||
bookable: true,
|
||||
duration_minutes: 30,
|
||||
insurance_covered: true,
|
||||
staff: { uuid: 'st1', full_name: 'مریم امینی' },
|
||||
staff_members: [{ uuid: 'st1', full_name: 'مریم امینی' }],
|
||||
created_at: 1_700_000_000,
|
||||
updated_at: 1_800_000_000,
|
||||
};
|
||||
|
||||
const mockApi = (item: unknown = ITEM, notFound = false) => {
|
||||
get.mockImplementation((url: string) => {
|
||||
if (url.includes('/subscription/my')) return Promise.resolve({ success: true, data: {
|
||||
subscription: null, used_trial: false,
|
||||
effective_plan: { name: 'professional', level: 2, max_secretaries: 10, features: { services: true } },
|
||||
} });
|
||||
if (url.includes('/payment/config')) return Promise.resolve({ success: true, data: { test_mode: true, gateways: [] } });
|
||||
if (url.includes('/service-item/')) {
|
||||
return notFound ? Promise.reject(new Error('یافت نشد')) : Promise.resolve({ success: true, data: item });
|
||||
}
|
||||
if (url.includes('/tariffs')) return Promise.resolve({ success: true, data: {
|
||||
current_year: 1404, default_price_rials: 8_500_000,
|
||||
data: [
|
||||
{ uuid: 't1', year: 1404, price_rials: 8_500_000, is_active: true },
|
||||
{ uuid: 't2', year: 1403, price_rials: 7_000_000, is_active: false },
|
||||
],
|
||||
} });
|
||||
if (url.includes('/tenant-insurances')) return Promise.resolve({ data: { data: [
|
||||
{ uuid: 'ins1', insurance_name: 'بیمه ایران', insurance_kind: 'basic', coverage_percent: 70 },
|
||||
] } });
|
||||
return Promise.resolve({ success: true, data: [] });
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
useAuthStore.setState({ primaryRole: 'doctor' });
|
||||
get.mockReset();
|
||||
mockApi();
|
||||
});
|
||||
|
||||
// صفحه uuid را از useParams میگیرد، پس به یک Route واقعی نیاز دارد.
|
||||
const render = () =>
|
||||
renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/admin/clinic-services/:uuid" element={<ServiceDetailPage />} />
|
||||
</Routes>,
|
||||
{ route: '/admin/clinic-services/it1' },
|
||||
);
|
||||
|
||||
describe('ServiceDetailPage (جزئیات سرویس)', () => {
|
||||
it('اطلاعات پایه سرویس را با breadcrumb نمایش میدهد', async () => {
|
||||
render();
|
||||
|
||||
expect(await screen.findByRole('heading', { name: 'سرم ۵۰۰cc' })).toBeInTheDocument();
|
||||
expect(screen.getByText('سرویسها')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('تزریقات').length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('مریم امینی')).toBeInTheDocument();
|
||||
expect(screen.getByText('۳۰ دقیقه')).toBeInTheDocument();
|
||||
expect(screen.getByText('تحت پوشش')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('تاریخ ایجاد و آخرین ویرایش را شمسی نشان میدهد', async () => {
|
||||
render();
|
||||
|
||||
expect(await screen.findByText('تاریخ ایجاد')).toBeInTheDocument();
|
||||
expect(screen.getByText('آخرین ویرایش')).toBeInTheDocument();
|
||||
// سال شمسی معادل ۱۷۰۰۰۰۰۰۰۰ ⇒ ۱۴۰۲
|
||||
expect(screen.getByText(/۱۴۰۲/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('تب تعرفهها فهرست سالها را با نشان «سال جاری» میآورد', async () => {
|
||||
render();
|
||||
fireEvent.click(await screen.findByText('تعرفهها'));
|
||||
|
||||
expect(await screen.findByText('سال جاری')).toBeInTheDocument();
|
||||
expect(screen.getByText('۱۴۰۴')).toBeInTheDocument();
|
||||
expect(screen.getByText('۱۴۰۳')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('تب بیمهها قراردادها و درصد پوشش را میآورد', async () => {
|
||||
render();
|
||||
fireEvent.click(await screen.findByText('بیمهها'));
|
||||
|
||||
expect(await screen.findByText('بیمه ایران')).toBeInTheDocument();
|
||||
expect(screen.getByText(/پوشش ۷۰٪/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('سرویس ناموجود → پیام خطا و دکمه بازگشت', async () => {
|
||||
mockApi(null, true);
|
||||
render();
|
||||
|
||||
expect(await screen.findByText('سرویس یافت نشد')).toBeInTheDocument();
|
||||
expect(screen.getByText('بازگشت به سرویسها')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('دکمه ویرایش، فرم مشترک سرویس را باز میکند', async () => {
|
||||
render();
|
||||
fireEvent.click(await screen.findByText('ویرایش'));
|
||||
|
||||
expect(await screen.findByText('ویرایش سرویس')).toBeInTheDocument();
|
||||
// تنظیمات بیمه نباید در فرم باشد
|
||||
expect(screen.queryByText('این خدمت شامل بیمه میشود')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('سرویس غیرفعال نشان «غیرفعال» و دکمه فعالکردن دارد', async () => {
|
||||
mockApi({ ...ITEM, active: false });
|
||||
render();
|
||||
|
||||
expect(await screen.findByText('غیرفعال')).toBeInTheDocument();
|
||||
expect(screen.getByText('فعالکردن')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user