import React from 'react';
import { getByText, waitFor } from '@testing-library/dom';
import { fireEvent, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';
import { DEFAULT_LGID_ROOT, getLgIds } from './getLgIds';
import { Pagination, type PaginationProps } from '.';
function renderPagination(props: PaginationProps) {
return render();
}
const onBackArrowClick = jest.fn();
const onForwardArrowClick = jest.fn();
const onItemsPerPageOptionChange = jest.fn();
const defaultProps: PaginationProps = {
numTotalItems: 1021,
itemsPerPageOptions: [10, 50, 100],
onItemsPerPageOptionChange,
onBackArrowClick,
onForwardArrowClick,
};
let offsetParentSpy: jest.SpyInstance;
beforeAll(() => {
offsetParentSpy = jest.spyOn(HTMLElement.prototype, 'offsetParent', 'get');
// JSDOM doesn't implement `HTMLElement.prototype.offsetParent`, so this
// falls back to the parent element since it doesn't matter for these tests.
offsetParentSpy.mockImplementation(function (this: HTMLElement) {
return this.parentElement;
});
});
afterAll(() => {
offsetParentSpy.mockRestore();
});
afterEach(() => {
jest.clearAllMocks();
});
describe('packages/pagination', () => {
describe('Pagination component', () => {
describe('a11y', () => {
test('does not have basic accessibility issues', async () => {
const { container } = renderPagination(defaultProps);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
describe('renders correctly', () => {
test('renders all pagination sections', () => {
const { getByTestId, getByText } = renderPagination(defaultProps);
// Items per page section
expect(getByText('Items per page:')).toBeInTheDocument();
expect(
getByTestId('leafygreen-ui-select-menubutton'),
).toBeInTheDocument();
// Range view section
expect(getByTestId('lg-pagination-item-range')).toBeInTheDocument();
// Current page controls section
expect(getByTestId('lg-pagination-page-range')).toBeInTheDocument();
expect(getByTestId('lg-pagination-back-button')).toBeInTheDocument();
expect(getByTestId('lg-pagination-next-button')).toBeInTheDocument();
});
test('applies custom className', () => {
const { getByTestId } = renderPagination({
...defaultProps,
className: 'custom-class',
});
expect(getByTestId('pagination-test')).toHaveClass('custom-class');
});
test('spreads rest props to container', () => {
const { getByTestId } = renderPagination({
...defaultProps,
'aria-label': 'Pagination navigation',
} as PaginationProps);
expect(getByTestId('pagination-test')).toHaveAttribute(
'aria-label',
'Pagination navigation',
);
});
});
describe('darkMode prop', () => {
test('renders in light mode by default', () => {
const { getByTestId } = renderPagination(defaultProps);
expect(getByTestId('pagination-test')).toBeInTheDocument();
});
test('renders in dark mode when darkMode prop is true', () => {
const { getByTestId } = renderPagination({
...defaultProps,
darkMode: true,
});
expect(getByTestId('pagination-test')).toBeInTheDocument();
});
});
describe('integration tests', () => {
test('items per page select works correctly', async () => {
const { getByTestId, queryByRole } = renderPagination(defaultProps);
const selectButton = getByTestId('leafygreen-ui-select-menubutton');
userEvent.click(selectButton);
const listbox = await waitFor(() => {
const listbox = queryByRole('listbox');
expect(listbox).toBeVisible();
return listbox as HTMLElement;
});
expect(getByText(listbox, '10')).toBeInTheDocument();
expect(getByText(listbox, '50')).toBeInTheDocument();
expect(getByText(listbox, '100')).toBeInTheDocument();
});
test('clicking back button calls onBackArrowClick', () => {
const { getByTestId } = renderPagination({
...defaultProps,
currentPage: 2,
});
const backButton = getByTestId('lg-pagination-back-button');
fireEvent.click(backButton);
expect(onBackArrowClick).toHaveBeenCalledTimes(1);
});
test('clicking forward button calls onForwardArrowClick', () => {
const { getByTestId } = renderPagination({
...defaultProps,
currentPage: 2,
});
const nextButton = getByTestId('lg-pagination-next-button');
fireEvent.click(nextButton);
expect(onForwardArrowClick).toHaveBeenCalledTimes(1);
});
test('does not render PaginationItemsPerPage when onItemsPerPageOptionChange is not provided', () => {
const { queryByText, queryByTestId } = renderPagination({
numTotalItems: 1021,
itemsPerPageOptions: [10, 50, 100],
onBackArrowClick,
onForwardArrowClick,
});
expect(queryByText('Items per page:')).not.toBeInTheDocument();
expect(
queryByTestId('leafygreen-ui-select-menubutton'),
).not.toBeInTheDocument();
});
});
describe('lgid props', () => {
const defaultLgIds = getLgIds();
test('renders default lgid values when data-lgid is not provided', () => {
const { getByTestId } = render();
expect(getByTestId(defaultLgIds.root)).toBeInTheDocument();
expect(getByTestId(defaultLgIds.pageSize)).toBeInTheDocument();
expect(getByTestId(defaultLgIds.summary)).toBeInTheDocument();
expect(getByTestId(defaultLgIds.navigation)).toBeInTheDocument();
});
test('renders default data-lgid attributes when data-lgid is not provided', () => {
const { getByTestId } = render();
expect(getByTestId(defaultLgIds.root)).toHaveAttribute(
'data-lgid',
DEFAULT_LGID_ROOT,
);
expect(getByTestId(defaultLgIds.pageSize)).toHaveAttribute(
'data-lgid',
`${DEFAULT_LGID_ROOT}-page_size`,
);
expect(getByTestId(defaultLgIds.summary)).toHaveAttribute(
'data-lgid',
`${DEFAULT_LGID_ROOT}-summary`,
);
expect(getByTestId(defaultLgIds.navigation)).toHaveAttribute(
'data-lgid',
`${DEFAULT_LGID_ROOT}-navigation`,
);
});
test('renders custom lgid values when data-lgid is provided', () => {
const customLgId = 'lg-my-pagination';
const customLgIds = getLgIds(customLgId);
const { getByTestId } = render(
,
);
expect(getByTestId(customLgIds.root)).toBeInTheDocument();
});
test('renders custom data-lgid attributes when data-lgid is provided', () => {
const customLgId = 'lg-my-pagination';
const customLgIds = getLgIds(customLgId);
const { getByTestId } = render(
,
);
expect(getByTestId(customLgIds.root)).toHaveAttribute(
'data-lgid',
customLgId,
);
});
});
});
});