import { describe, it, expect } from 'vitest'; import { render, screen, fireEvent } from '@testing-library/react'; import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom'; import { useUrlState, pageOf } from './useUrlState'; import BackButton from '../components/ui/BackButton'; /** * قرارداد: وضعیت لیست در URL است، پس «بازگشت» (که همان URL قبلی را برمی‌گرداند) * فیلتر و صفحه را هم برمی‌گرداند. */ function ListPage() { const [state, setState] = useUrlState({ page: '1', search: '', status: '' }); const location = useLocation(); return (
{location.search} {`${state.page}|${state.search}|${state.status}`} { e.preventDefault(); window.history.pushState({}, '', '/detail'); }}>x
); } function DetailPage() { return ( <> جزئیات ); } function renderApp(entries: string[] = ['/list']) { return render( } /> } /> , ); } describe('useUrlState', () => { it('مقدار اولیه را از URL می‌خواند', () => { renderApp(['/list?page=2&search=علی&status=paid']); expect(screen.getByTestId('state')).toHaveTextContent('2|علی|paid'); }); it('تغییر فیلتر در query string می‌نشیند و صفحه را یک می‌کند', () => { renderApp(['/list?page=4']); fireEvent.click(screen.getByText('فیلتر')); expect(screen.getByTestId('qs').textContent).toContain('status=paid'); expect(screen.getByTestId('state')).toHaveTextContent('1|'); }); it('مقدارِ برابرِ پیش‌فرض از URL حذف می‌شود', () => { renderApp(['/list?page=3']); fireEvent.click(screen.getByText('صفحه ۳')); expect(screen.getByTestId('qs').textContent).toContain('page=3'); fireEvent.click(screen.getByText('فیلتر')); // page → '1' = پیش‌فرض expect(screen.getByTestId('qs').textContent).not.toContain('page='); }); it('دو تغییرِ پشت‌سرهم در یک handler همدیگر را پاک نمی‌کنند', () => { renderApp(['/list']); fireEvent.click(screen.getByText('دو تغییر پشت‌سرهم')); // مودالِ فیلتر دقیقاً همین کار را می‌کند: setFilters(...) و بعد setPage(1). expect(screen.getByTestId('state')).toHaveTextContent('2||paid'); }); it('بازگشت از صفحهٔ جزئیات، فیلتر و صفحهٔ لیست را دست‌نخورده برمی‌گرداند', () => { render( } /> } /> , ); expect(screen.getByText('جزئیات')).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: /بازگشت/ })); expect(screen.getByTestId('state')).toHaveTextContent('3|مریم|paid'); }); it('pageOf مقدار نامعتبر را به ۱ می‌برد', () => { expect(pageOf('')).toBe(1); expect(pageOf('0')).toBe(1); expect(pageOf('abc')).toBe(1); expect(pageOf('7')).toBe(7); }); });