408 lines
11 KiB
TypeScript
408 lines
11 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { render, screen } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { TrackListPagination } from './TrackListPagination';
|
|
|
|
describe('TrackListPagination', () => {
|
|
const mockOnPageChange = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should render pagination', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
expect(
|
|
screen.getByRole('navigation', {
|
|
name: 'Pagination de la liste de pistes',
|
|
}),
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('should display current page information', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={2}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
expect(screen.getByText(/Affichage de/)).toBeInTheDocument();
|
|
expect(screen.getByText(/11/)).toBeInTheDocument();
|
|
expect(screen.getByText(/20/)).toBeInTheDocument();
|
|
expect(screen.getByText(/50/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('should display page numbers', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
showPageNumbers={true}
|
|
/>,
|
|
);
|
|
expect(screen.getByLabelText('Aller à la page 1')).toBeInTheDocument();
|
|
expect(screen.getByLabelText('Aller à la page 2')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should highlight current page', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={3}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
const currentPageButton = screen.getByLabelText('Aller à la page 3');
|
|
expect(currentPageButton).toHaveAttribute('aria-current', 'page');
|
|
expect(currentPageButton).toHaveClass('bg-blue-600');
|
|
});
|
|
|
|
it('should call onPageChange when page number is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const page2Button = screen.getByLabelText('Aller à la page 2');
|
|
await user.click(page2Button);
|
|
|
|
expect(mockOnPageChange).toHaveBeenCalledWith(2);
|
|
});
|
|
|
|
it('should call onPageChange when next button is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const nextButton = screen.getByLabelText('Page suivante');
|
|
await user.click(nextButton);
|
|
|
|
expect(mockOnPageChange).toHaveBeenCalledWith(2);
|
|
});
|
|
|
|
it('should call onPageChange when previous button is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={2}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const previousButton = screen.getByLabelText('Page précédente');
|
|
await user.click(previousButton);
|
|
|
|
expect(mockOnPageChange).toHaveBeenCalledWith(1);
|
|
});
|
|
|
|
it('should call onPageChange when first page button is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={3}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const firstButton = screen.getByLabelText('Aller à la première page');
|
|
await user.click(firstButton);
|
|
|
|
expect(mockOnPageChange).toHaveBeenCalledWith(1);
|
|
});
|
|
|
|
it('should call onPageChange when last page button is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const lastButton = screen.getByLabelText('Aller à la dernière page');
|
|
await user.click(lastButton);
|
|
|
|
expect(mockOnPageChange).toHaveBeenCalledWith(5);
|
|
});
|
|
|
|
it('should disable previous button on first page', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const previousButton = screen.getByLabelText('Page précédente');
|
|
const firstButton = screen.getByLabelText('Aller à la première page');
|
|
|
|
expect(previousButton).toBeDisabled();
|
|
expect(firstButton).toBeDisabled();
|
|
});
|
|
|
|
it('should disable next button on last page', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={5}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const nextButton = screen.getByLabelText('Page suivante');
|
|
const lastButton = screen.getByLabelText('Aller à la dernière page');
|
|
|
|
expect(nextButton).toBeDisabled();
|
|
expect(lastButton).toBeDisabled();
|
|
});
|
|
|
|
it('should show ellipsis when there are many pages', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={5}
|
|
totalPages={10}
|
|
totalItems={100}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
maxVisiblePages={5}
|
|
/>,
|
|
);
|
|
|
|
const ellipsis = screen.queryAllByText('...');
|
|
expect(ellipsis.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should limit visible page numbers based on maxVisiblePages', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={5}
|
|
totalPages={20}
|
|
totalItems={200}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
maxVisiblePages={5}
|
|
/>,
|
|
);
|
|
|
|
// Should show around 5 pages centered on current page
|
|
const pageButtons = screen.getAllByLabelText(/Aller à la page \d+/);
|
|
expect(pageButtons.length).toBeLessThanOrEqual(7); // 5 visible + first + last potentially
|
|
});
|
|
|
|
it('should hide page numbers when showPageNumbers is false', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
showPageNumbers={false}
|
|
/>,
|
|
);
|
|
|
|
const pageButtons = screen.queryAllByLabelText(/Aller à la page \d+/);
|
|
expect(pageButtons.length).toBe(0);
|
|
});
|
|
|
|
it('should hide items info when showItemsInfo is false', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
showItemsInfo={false}
|
|
/>,
|
|
);
|
|
|
|
expect(screen.queryByText(/Affichage de/)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('should return null when totalPages is 1 and showItemsInfo is false', () => {
|
|
const { container } = render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={1}
|
|
totalItems={10}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
showItemsInfo={false}
|
|
/>,
|
|
);
|
|
|
|
expect(container.firstChild).toBeNull();
|
|
});
|
|
|
|
it('should disable all buttons when disabled prop is true', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={3}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
disabled={true}
|
|
/>,
|
|
);
|
|
|
|
const nextButton = screen.getByLabelText('Page suivante');
|
|
const previousButton = screen.getByLabelText('Page précédente');
|
|
const pageButton = screen.getByLabelText('Aller à la page 2');
|
|
|
|
expect(nextButton).toBeDisabled();
|
|
expect(previousButton).toBeDisabled();
|
|
expect(pageButton).toBeDisabled();
|
|
});
|
|
|
|
it('should not call onPageChange when clicking disabled buttons', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const previousButton = screen.getByLabelText('Page précédente');
|
|
await user.click(previousButton);
|
|
|
|
expect(mockOnPageChange).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not call onPageChange when clicking current page', async () => {
|
|
const user = userEvent.setup();
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={2}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const currentPageButton = screen.getByLabelText('Aller à la page 2');
|
|
await user.click(currentPageButton);
|
|
|
|
expect(mockOnPageChange).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should apply custom className', () => {
|
|
const { container } = render(
|
|
<TrackListPagination
|
|
currentPage={1}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
className="custom-class"
|
|
/>,
|
|
);
|
|
|
|
const nav = container.querySelector('[role="navigation"]');
|
|
expect(nav).toHaveClass('custom-class');
|
|
});
|
|
|
|
it('should calculate correct item range', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={3}
|
|
totalPages={5}
|
|
totalItems={47}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
// Page 3: items 21-30, but total is 47, so 21-30
|
|
expect(screen.getByText(/21/)).toBeInTheDocument();
|
|
expect(screen.getByText(/30/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle edge case with last page having fewer items', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={5}
|
|
totalPages={5}
|
|
totalItems={47}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
// Last page: items 41-47
|
|
expect(screen.getByText(/41/)).toBeInTheDocument();
|
|
// Check for "47" in the range display (not just anywhere)
|
|
const infoText = screen.getByText(/Affichage de/);
|
|
expect(infoText.textContent).toContain('47');
|
|
});
|
|
|
|
it('should have accessible attributes', () => {
|
|
render(
|
|
<TrackListPagination
|
|
currentPage={2}
|
|
totalPages={5}
|
|
totalItems={50}
|
|
itemsPerPage={10}
|
|
onPageChange={mockOnPageChange}
|
|
/>,
|
|
);
|
|
|
|
const nav = screen.getByRole('navigation');
|
|
expect(nav).toHaveAttribute(
|
|
'aria-label',
|
|
'Pagination de la liste de pistes',
|
|
);
|
|
|
|
const currentPageButton = screen.getByLabelText('Aller à la page 2');
|
|
expect(currentPageButton).toHaveAttribute('aria-current', 'page');
|
|
});
|
|
});
|