import { describe, it, expect, vi } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import Pagination from '@/components/ui/Pagination'; import StatusBadge, { ActiveBadge } from '@/components/ui/StatusBadge'; import ConfirmDialog from '@/components/ui/ConfirmDialog'; import MobileInput from '@/components/ui/MobileInput'; describe('Pagination', () => { it('وقتی یک صفحه یا کمتر است چیزی رندر نمی‌کند', () => { const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('دکمه «قبلی» در صفحه اول غیرفعال است', () => { render(); const buttons = screen.getAllByRole('button'); expect(buttons[0]).toBeDisabled(); // prev expect(buttons[buttons.length - 1]).not.toBeDisabled(); // next }); it('کلیک «بعدی» صفحه page+1 را می‌فرستد', async () => { const onPage = vi.fn(); render(); const buttons = screen.getAllByRole('button'); await userEvent.click(buttons[buttons.length - 1]); expect(onPage).toHaveBeenCalledWith(2); }); it('کلیک روی شماره صفحه همان شماره را می‌فرستد', async () => { const onPage = vi.fn(); render(); await userEvent.click(screen.getByText('۳')); expect(onPage).toHaveBeenCalledWith(3); }); }); describe('StatusBadge', () => { it.each([ ['appointment', 'confirmed', 'تأیید شده'], ['appointment', 'no_show', 'غیبت'], ['payment', 'success', 'موفق'], ['sms', 'approved', 'تأیید شده'], ['settlement', 'rejected', 'رد شده'], ])('%s/%s → %s', (type, value, label) => { render(); expect(screen.getByText(label)).toBeInTheDocument(); }); it('مقدار ناشناخته → خود مقدار نمایش داده می‌شود', () => { render(); expect(screen.getByText('zzz')).toBeInTheDocument(); }); it('ActiveBadge فعال/غیرفعال', () => { const { rerender } = render(); expect(screen.getByText('فعال')).toBeInTheDocument(); rerender(); expect(screen.getByText('غیرفعال')).toBeInTheDocument(); }); }); describe('ConfirmDialog', () => { it('وقتی open=false چیزی رندر نمی‌شود', () => { const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('تأیید و لغو callbackهای درست را صدا می‌زنند', async () => { const onConfirm = vi.fn(); const onCancel = vi.fn(); render( , ); await userEvent.click(screen.getByRole('button', { name: 'تأیید' })); expect(onConfirm).toHaveBeenCalledTimes(1); await userEvent.click(screen.getByRole('button', { name: 'لغو' })); expect(onCancel).toHaveBeenCalledTimes(1); }); it('در حالت loading دکمه‌ها غیرفعال و متن «در حال انجام...» است', () => { render( , ); expect(screen.getByText('در حال انجام...')).toBeInTheDocument(); screen.getAllByRole('button').forEach((b) => { if (b.textContent) expect(b).toBeDisabled(); }); }); }); describe('MobileInput', () => { it('ارقام فارسی و جداکننده را قبل از onChange نرمال می‌کند', () => { const onChange = vi.fn(); render(); const input = screen.getByRole('textbox'); fireEvent.change(input, { target: { value: '۰۹۱۲-۳۴۵ ۶۷۸۹' } }); expect(onChange).toHaveBeenCalled(); const evt = onChange.mock.calls[0][0]; expect(evt.target.value).toBe('09123456789'); }); it('placeholder پیش‌فرض و maxLength=11 دارد', () => { render(); const input = screen.getByPlaceholderText('09xxxxxxxxx') as HTMLInputElement; expect(input.maxLength).toBe(11); expect(input.getAttribute('dir')).toBe('ltr'); }); });