import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Deck, { DeckButton } from './Deck';
import { ButtonVariant } from '@patternfly/react-core';
describe('Deck component', () => {
const mockPages = [
{
content:
Page 1 content
,
buttons: [
{
children: 'Next',
variant: ButtonVariant.primary,
navigation: 'next' as const
}
] as DeckButton[]
},
{
content: Page 2 content
,
buttons: [
{
children: 'Previous',
variant: ButtonVariant.secondary,
navigation: 'previous' as const
},
{
children: 'Next',
variant: ButtonVariant.primary,
navigation: 'next' as const
}
] as DeckButton[]
},
{
content: Page 3 content
,
buttons: [
{
children: 'Close',
variant: ButtonVariant.primary,
navigation: 'close' as const
}
] as DeckButton[]
}
];
test('should render with basic pages', () => {
const pages = [
{
content: Page 1 content
,
buttons: []
}
];
const { container } = render();
expect(container).toMatchSnapshot();
});
test('should render first page content by default', () => {
render();
expect(screen.getByText('Page 1 content')).toBeInTheDocument();
});
test('should render with hideProgressDots', () => {
const pages = [
{
content: Page 1 content
,
buttons: []
}
];
const { container } = render(
);
const progressDots = container.querySelector('[data-ouia-component-id="Deck-progress-dots"]');
expect(progressDots).not.toBeInTheDocument();
});
test('should not render progress dots when only one page', () => {
const pages = [
{
content: Single page
,
buttons: []
}
];
const { container } = render();
const progressDots = container.querySelector('[data-ouia-component-id="Deck-progress-dots"]');
expect(progressDots).not.toBeInTheDocument();
});
test('should navigate to next page when next button is clicked', async () => {
const user = userEvent.setup();
render();
expect(screen.getByText('Page 1 content')).toBeInTheDocument();
const nextButton = screen.getByRole('button', { name: 'Next' });
await user.click(nextButton);
expect(screen.getByText('Page 2 content')).toBeInTheDocument();
});
test('should navigate to previous page when previous button is clicked', async () => {
const user = userEvent.setup();
render();
expect(screen.getByText('Page 2 content')).toBeInTheDocument();
const previousButton = screen.getByRole('button', { name: 'Previous' });
await user.click(previousButton);
expect(screen.getByText('Page 1 content')).toBeInTheDocument();
});
test('should call onClose when close button is clicked', async () => {
const user = userEvent.setup();
const onClose = jest.fn();
render();
const closeButton = screen.getByRole('button', { name: 'Close' });
await user.click(closeButton);
expect(onClose).toHaveBeenCalledTimes(1);
});
test('should call onPageChange callback when page changes', async () => {
const user = userEvent.setup();
const onPageChange = jest.fn();
render();
const nextButton = screen.getByRole('button', { name: 'Next' });
await user.click(nextButton);
expect(onPageChange).toHaveBeenCalledWith(1);
});
test('should call custom onClick before navigation', async () => {
const user = userEvent.setup();
const customOnClick = jest.fn();
const pagesWithCustomClick = [
{
content: Page 1
,
buttons: [
{
children: 'Next',
variant: ButtonVariant.primary,
navigation: 'next' as const,
onClick: customOnClick
}
] as DeckButton[]
},
{
content: Page 2
,
buttons: []
}
];
render();
const nextButton = screen.getByRole('button', { name: 'Next' });
await user.click(nextButton);
expect(customOnClick).toHaveBeenCalledTimes(1);
expect(screen.getByText('Page 2')).toBeInTheDocument();
});
test('should start at initialPage', () => {
render();
expect(screen.getByText('Page 2 content')).toBeInTheDocument();
});
test('should render with custom OUIA ID', () => {
const { container } = render();
const element = container.querySelector('[data-ouia-component-id="CustomDeck"]');
expect(element).toBeInTheDocument();
});
test('should apply custom text alignment class', () => {
const { container } = render();
const contentElement = container.querySelector('[data-ouia-component-id="Deck-content"]');
expect(contentElement).toHaveClass('pf-v6-u-text-align-left');
});
test('should not apply text alignment class when textAlign is false', () => {
const { container } = render();
const contentElement = container.querySelector('[data-ouia-component-id="Deck-content"]');
expect(contentElement).not.toHaveClass('pf-v6-u-text-align-center');
});
test('should render with custom aria labels', () => {
const { container } = render(
);
const region = container.querySelector('[role="region"]');
expect(region).toHaveAttribute('aria-label', 'Custom deck label');
expect(region).toHaveAttribute('aria-roledescription', 'Custom role description');
});
test('should render accessible page info for screen readers', () => {
const { container } = render();
const pageInfo = container.querySelector('.pf-v6-screen-reader');
expect(pageInfo).toBeInTheDocument();
expect(pageInfo).toHaveTextContent('Page 1 of 3');
});
test('should update page info when page changes', async () => {
const user = userEvent.setup();
const { container } = render();
const nextButton = screen.getByRole('button', { name: 'Next' });
await user.click(nextButton);
const pageInfo = container.querySelector('.pf-v6-screen-reader');
expect(pageInfo).toHaveTextContent('Page 2 of 3');
});
test('should use custom getPageLabel function', () => {
const getPageLabel = (current: number, total: number) => `Step ${current}/${total}`;
const { container } = render(
);
const pageInfo = container.querySelector('.pf-v6-screen-reader');
expect(pageInfo).toHaveTextContent('Step 1/3');
});
test('should render correct number of progress dots', () => {
const { container } = render();
const dots = container.querySelectorAll('[data-ouia-component-id="Deck-progress-dots"] span[aria-hidden="true"]');
expect(dots).toHaveLength(3);
});
test('should not navigate beyond last page', async () => {
const onPageChange = jest.fn();
render();
expect(screen.getByText('Page 3 content')).toBeInTheDocument();
// There's no next button on the last page in our mock, so the page shouldn't change
// This tests the boundary condition
expect(onPageChange).not.toHaveBeenCalled();
});
test('should not navigate before first page', async () => {
const onPageChange = jest.fn();
render();
expect(screen.getByText('Page 1 content')).toBeInTheDocument();
// There's no previous button on the first page in our mock
expect(onPageChange).not.toHaveBeenCalled();
});
});