import { render, screen, userEvent } from '../test-utils';
import Tabs, { TabsProps } from './Tabs';
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTimeAsync });
if (typeof performance === 'undefined') {
global.performance = { now: () => Date.now() } as Performance;
}
const defaultTabsStatus = [false, true, false];
function generateTabs(tabsStatus = defaultTabsStatus) {
return tabsStatus.map((disabled, index) => ({
disabled,
title: `Title ${index}`,
content:
Content {index}
,
}));
}
describe('Tabs', () => {
const initialProps: TabsProps = {
tabs: generateTabs(),
changeTabOnSwipe: true,
name: 'testName',
headerWidth: 'block',
selected: 0,
onTabSelect: jest.fn(),
className: 'custom-class-name',
};
beforeEach(() => {
jest.clearAllMocks();
jest.useFakeTimers();
});
afterEach(async () => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
it('should render a tablist', () => {
render();
expect(screen.getByRole('tablist')).toBeInTheDocument();
});
it('should respect className', () => {
render();
expect(screen.getByRole('tablist').parentNode).toHaveClass(String(initialProps.className));
});
it('should respect `name` prop', () => {
render();
const controlsTarget = screen
.getByRole('tab', { selected: true })
.getAttribute('aria-controls');
expect(screen.getByRole('tabpanel')).toHaveAttribute('id', controlsTarget);
});
it('should render correct number of tabs', () => {
render();
expect(screen.getAllByRole('tab')).toHaveLength(defaultTabsStatus.length);
initialProps.tabs.forEach(({ title }) => {
expect(screen.getByText(title)).toBeInTheDocument();
});
});
it('should show first tab content by default', () => {
render();
expect(screen.getAllByRole('tabpanel')).toHaveLength(1);
expect(screen.getByTestId('content-0')).toBeInTheDocument();
});
describe('tab switch', () => {
it('should call onTabSelecton on click', async () => {
render();
const thirdTab = screen.getAllByRole('tab')[2];
await user.click(thirdTab);
// It's called on mount first, that's why the count is at 2
expect(initialProps.onTabSelect).toHaveBeenCalledTimes(2);
expect(initialProps.onTabSelect).toHaveBeenCalledWith(2);
});
it('should call onTabSelecton when navigating with keyboard', async () => {
render();
await user.keyboard('{Tab}{Tab}{Tab}{Enter}');
// It's called on mount first, that's why the count is at 2
expect(initialProps.onTabSelect).toHaveBeenCalledTimes(2);
expect(initialProps.onTabSelect).toHaveBeenCalledWith(2);
});
it('should call onTabSelecton on swipe', async () => {
render();
await user.keyboard('{Tab}{Tab}{Tab}{Enter}');
// It's called on mount first, that's why the count is at 2
expect(initialProps.onTabSelect).toHaveBeenCalledTimes(2);
expect(initialProps.onTabSelect).toHaveBeenCalledWith(2);
});
it('should highlight selected tab', async () => {
const { rerender } = render();
rerender();
expect(screen.getByRole('tab', { selected: true })).toHaveTextContent('Title 2');
});
it('should switch content tab', async () => {
const { rerender } = render();
rerender();
expect(screen.getByRole('tabpanel')).toHaveTextContent('Content 2');
});
});
});