From fc45491c09dac90613bc4581f31ecf7ba0086751 Mon Sep 17 00:00:00 2001 From: Ariella Gilmore Date: Wed, 9 Oct 2024 09:57:34 -0600 Subject: [PATCH] test(tabs): increase coverage (#17565) --- .../Tabs/{ => __tests__}/Tabs-test.js | 236 +++++++++++++++++- .../Tabs/__tests__/Tabs.Skeleton-test.js | 22 ++ .../react/src/components/Tabs/usePressable.js | 2 + 3 files changed, 258 insertions(+), 2 deletions(-) rename packages/react/src/components/Tabs/{ => __tests__}/Tabs-test.js (76%) create mode 100644 packages/react/src/components/Tabs/__tests__/Tabs.Skeleton-test.js diff --git a/packages/react/src/components/Tabs/Tabs-test.js b/packages/react/src/components/Tabs/__tests__/Tabs-test.js similarity index 76% rename from packages/react/src/components/Tabs/Tabs-test.js rename to packages/react/src/components/Tabs/__tests__/Tabs-test.js index 759921a7fe1e..e3a346a9f535 100644 --- a/packages/react/src/components/Tabs/Tabs-test.js +++ b/packages/react/src/components/Tabs/__tests__/Tabs-test.js @@ -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'; @@ -255,6 +255,78 @@ describe('Tab', () => { expect(onKeyDown).toHaveBeenCalled(); }); + it('should go to the next tab using arrow keys', async () => { + render( + + + Tab Label 1 + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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( + + + Tab Label 1 + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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( {}}> @@ -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( + {}}> + + Tab Label 1 + + Tab Label 2 + + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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( @@ -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( + + + Tab Label 1 + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + expect(container.firstChild).not.toHaveClass(`${prefix}--tabs--vertical`); + }); + + it('should go to the next tab using arrow keys', async () => { + render( + + + Tab Label 1 + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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( + + + Tab Label 1 + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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( + + + + Tab Label 1 + + Tab Label 2 + Tab Label 3 + + + Tab Panel 1 + Tab Panel 2 + Tab Panel 3 + + + ); + + 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(); diff --git a/packages/react/src/components/Tabs/__tests__/Tabs.Skeleton-test.js b/packages/react/src/components/Tabs/__tests__/Tabs.Skeleton-test.js new file mode 100644 index 000000000000..e295681d5a05 --- /dev/null +++ b/packages/react/src/components/Tabs/__tests__/Tabs.Skeleton-test.js @@ -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(); + expect(container.firstChild).toHaveClass('test'); + }); + + it('should spread additional props on the outermost element', () => { + const { container } = render(); + expect(container.firstChild).toHaveAttribute('data-testid', 'test'); + }); +}); diff --git a/packages/react/src/components/Tabs/usePressable.js b/packages/react/src/components/Tabs/usePressable.js index baf12d70ad70..fcf32b31c3ca 100644 --- a/packages/react/src/components/Tabs/usePressable.js +++ b/packages/react/src/components/Tabs/usePressable.js @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +/* istanbul ignore file */ + import { useEffect, useRef, useState } from 'react'; /**