import { describe, it, expect, afterEach, vi } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import Pagination from './Pagination.svelte'; afterEach(() => { cleanup(); }); const makeHref = (p: number) => `/documents?page=${p}`; describe('Pagination', () => { it('renders the page-of-total label for the current page', async () => { render(Pagination, { page: 2, totalPages: 10, makeHref }); const label = page.getByTestId('pagination-page-label'); await expect.element(label).toHaveTextContent(/3/); // page is 0-indexed, label is 1-indexed await expect.element(label).toHaveTextContent(/10/); }); it('marks the current page label with aria-current="page"', async () => { render(Pagination, { page: 0, totalPages: 3, makeHref }); const label = page.getByTestId('pagination-page-label'); await expect.element(label).toHaveAttribute('aria-current', 'page'); }); it('renders prev as a link pointing at page - 1 when not on first page', async () => { render(Pagination, { page: 4, totalPages: 10, makeHref }); const prev = page.getByTestId('pagination-prev'); await expect.element(prev).toHaveAttribute('href', '/documents?page=3'); }); it('disables prev on page 0 (no href, aria-disabled="true")', async () => { render(Pagination, { page: 0, totalPages: 3, makeHref }); const prev = page.getByTestId('pagination-prev'); await expect.element(prev).toHaveAttribute('aria-disabled', 'true'); await expect.element(prev).not.toHaveAttribute('href'); }); it('renders next as a link pointing at page + 1 when not on last page', async () => { render(Pagination, { page: 0, totalPages: 3, makeHref }); const next = page.getByTestId('pagination-next'); await expect.element(next).toHaveAttribute('href', '/documents?page=1'); }); it('disables next on the last page (no href, aria-disabled="true")', async () => { render(Pagination, { page: 2, totalPages: 3, makeHref }); const next = page.getByTestId('pagination-next'); await expect.element(next).toHaveAttribute('aria-disabled', 'true'); await expect.element(next).not.toHaveAttribute('href'); }); it('calls makeHref with p-1 and p+1', async () => { const spy = vi.fn(makeHref); render(Pagination, { page: 3, totalPages: 10, makeHref: spy }); const calls = spy.mock.calls.map((c) => c[0]).sort((a, b) => a - b); expect(calls).toContain(2); expect(calls).toContain(4); }); it('renders decorative chevron inside aria-hidden span so screen readers skip it', async () => { render(Pagination, { page: 1, totalPages: 3, makeHref }); const prev = page.getByTestId('pagination-prev'); await expect .element(prev.getByText('«', { exact: true })) .toHaveAttribute('aria-hidden', 'true'); }); it('prev and next have min 44px touch targets', async () => { render(Pagination, { page: 1, totalPages: 3, makeHref }); const prev = page.getByTestId('pagination-prev'); await expect.element(prev).toHaveClass(/min-h-\[44px\]/); await expect.element(prev).toHaveClass(/min-w-\[44px\]/); }); });