Skip to content

Commit

Permalink
test(tabs): increase coverage (#17565)
Browse files Browse the repository at this point in the history
  • Loading branch information
ariellalgilmore authored Oct 9, 2024
1 parent 7073e7a commit fc45491
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import {
TabPanels,
TabList,
TabListVertical,
} from './Tabs';
} from '../Tabs';
import { act } from 'react';

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as hooks from '../../internal/useMatchMedia';
import * as hooks from '../../../internal/useMatchMedia';

const prefix = 'cds';

Expand Down Expand Up @@ -255,6 +255,78 @@ describe('Tab', () => {
expect(onKeyDown).toHaveBeenCalled();
});

it('should go to the next tab using arrow keys', async () => {
render(
<Tabs>
<TabList aria-label="List of tabs">
<Tab data-testid="tab-testid-1">Tab Label 1</Tab>
<Tab data-testid="tab-testid-2">Tab Label 2</Tab>
<Tab data-testid="tab-testid-3">Tab Label 3</Tab>
</TabList>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</Tabs>
);

await userEvent.tab();
await userEvent.keyboard('[ArrowRight]');

expect(screen.getByTestId('tab-testid-2')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[ArrowLeft]');

expect(screen.getByTestId('tab-testid-1')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[End]');

expect(screen.getByTestId('tab-testid-3')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[Home]');

expect(screen.getByTestId('tab-testid-1')).toHaveAttribute(
'aria-selected',
'true'
);
});

it('should go to the next tab with manual activation', async () => {
render(
<Tabs>
<TabList aria-label="List of tabs" activation="manual">
<Tab data-testid="tab-testid-1">Tab Label 1</Tab>
<Tab data-testid="tab-testid-2">Tab Label 2</Tab>
<Tab data-testid="tab-testid-3">Tab Label 3</Tab>
</TabList>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</Tabs>
);

await userEvent.tab();
await userEvent.keyboard('[ArrowRight]');
await userEvent.keyboard('[Space]');

expect(screen.getByTestId('tab-testid-2')).toHaveAttribute(
'aria-selected',
'true'
);
});

it('should render close icon if dismissable', () => {
render(
<Tabs dismissable onTabCloseRequest={() => {}}>
Expand All @@ -278,6 +350,36 @@ describe('Tab', () => {
).not.toHaveClass(`${prefix}--visually-hidden`);
});

it('should ignore hover on dismissable icon if it is a contained tab', async () => {
render(
<Tabs dismissable onTabCloseRequest={() => {}}>
<TabList contained aria-label="List of tabs">
<Tab>Tab Label 1</Tab>
<Tab disabled data-testid="tab-testid">
Tab Label 2
</Tab>
<Tab>Tab Label 3</Tab>
</TabList>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</Tabs>
);

const tab = screen.getByTestId('tab-testid');
const tabIcon = screen.getAllByLabelText(
'Press delete to remove Tab Label 2 tab'
)[0].parentElement;

await userEvent.hover(tabIcon);
expect(tab).toHaveClass('cds--tabs__nav-item--hover-off');

await userEvent.unhover(tabIcon);
expect(tab).not.toHaveClass('cds--tabs__nav-item--hover-off');
});

it('should not render close icon if not dismissable', () => {
render(
<Tabs>
Expand Down Expand Up @@ -463,6 +565,136 @@ describe('Tab', () => {
});
});

describe('TabsVertical', () => {
beforeEach(() => {
jest.resetModules();
jest.spyOn(hooks, 'useMatchMedia').mockImplementation(() => false);
});

it('should render as horizontal tab in sm breakpoint', () => {
jest.spyOn(hooks, 'useMatchMedia').mockImplementation(() => true);

const { container } = render(
<TabsVertical>
<TabListVertical aria-label="List of tabs">
<Tab>Tab Label 1</Tab>
<Tab>Tab Label 2</Tab>
<Tab>Tab Label 3</Tab>
</TabListVertical>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</TabsVertical>
);

expect(container.firstChild).not.toHaveClass(`${prefix}--tabs--vertical`);
});

it('should go to the next tab using arrow keys', async () => {
render(
<TabsVertical>
<TabListVertical aria-label="List of tabs">
<Tab data-testid="tab-testid-1">Tab Label 1</Tab>
<Tab data-testid="tab-testid-2">Tab Label 2</Tab>
<Tab data-testid="tab-testid-3">Tab Label 3</Tab>
</TabListVertical>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</TabsVertical>
);

await userEvent.tab();
await userEvent.keyboard('[ArrowDown]');

expect(screen.getByTestId('tab-testid-2')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[ArrowUp]');

expect(screen.getByTestId('tab-testid-1')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[End]');

expect(screen.getByTestId('tab-testid-3')).toHaveAttribute(
'aria-selected',
'true'
);

await userEvent.keyboard('[Home]');

expect(screen.getByTestId('tab-testid-1')).toHaveAttribute(
'aria-selected',
'true'
);
});

it('should go to the next tab with manual activation', async () => {
render(
<TabsVertical>
<TabListVertical aria-label="List of tabs" activation="manual">
<Tab data-testid="tab-testid-1">Tab Label 1</Tab>
<Tab data-testid="tab-testid-2">Tab Label 2</Tab>
<Tab data-testid="tab-testid-3">Tab Label 3</Tab>
</TabListVertical>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</TabsVertical>
);

await userEvent.tab();
await userEvent.keyboard('[ArrowDown]');
await userEvent.keyboard('[Space]');

expect(screen.getByTestId('tab-testid-2')).toHaveAttribute(
'aria-selected',
'true'
);
});

it('should not select a disabled tab and select next tab', () => {
render(
<TabsVertical>
<TabListVertical aria-label="List of tabs">
<Tab data-testid="tab-testid-1" disabled>
Tab Label 1
</Tab>
<Tab data-testid="tab-testid-2">Tab Label 2</Tab>
<Tab>Tab Label 3</Tab>
</TabListVertical>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</TabsVertical>
);

expect(screen.getByTestId('tab-testid-1')).toHaveAttribute(
'aria-selected',
'false'
);

// By default, if a Tab is disabled, the next Tab should be selected
expect(screen.getByTestId('tab-testid-2')).toHaveAttribute(
'aria-selected',
'true'
);
});
});

describe('TabPanel', () => {
beforeEach(() => {
jest.resetModules();
Expand Down
22 changes: 22 additions & 0 deletions packages/react/src/components/Tabs/__tests__/Tabs.Skeleton-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import { TabsSkeleton } from '../Tabs.Skeleton';
import { render } from '@testing-library/react';

describe('TabsSkeleton', () => {
it('should support a custom `className` prop on the outermost element', () => {
const { container } = render(<TabsSkeleton className="test" />);
expect(container.firstChild).toHaveClass('test');
});

it('should spread additional props on the outermost element', () => {
const { container } = render(<TabsSkeleton data-testid="test" />);
expect(container.firstChild).toHaveAttribute('data-testid', 'test');
});
});
2 changes: 2 additions & 0 deletions packages/react/src/components/Tabs/usePressable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

/* istanbul ignore file */

import { useEffect, useRef, useState } from 'react';

/**
Expand Down

0 comments on commit fc45491

Please sign in to comment.