From b45e1e8a914bb03eb8ad726cdec44bc49f29df69 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Wed, 8 Jan 2025 10:10:33 -0800 Subject: [PATCH] test: update test cases --- .../tests/ControlledSelectHeader.test.jsx | 10 +-- src/DataTable/tests/DataViewToggle.test.jsx | 10 +-- src/Dropdown/deprecated/Dropdown.test.jsx | 70 ++++++++++++------- src/Form/tests/FormCheckboxSet.test.jsx | 5 +- src/Form/tests/FormControl.test.jsx | 15 ++-- src/Form/tests/FormRadioSet.test.jsx | 5 +- .../IconButtonToggle.test.jsx | 5 +- src/ListBox/ListBox.test.jsx | 12 ++-- src/Modal/tests/ModalLayer.test.tsx | 5 +- src/ProductTour/Checkpoint.test.jsx | 5 +- src/StatusAlert/StatusAlert.test.jsx | 8 ++- src/Tabs/deprecated/Tabs.test.jsx | 10 +-- 12 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/DataTable/selection/tests/ControlledSelectHeader.test.jsx b/src/DataTable/selection/tests/ControlledSelectHeader.test.jsx index 2af2b283ba..c2b48bf5d4 100644 --- a/src/DataTable/selection/tests/ControlledSelectHeader.test.jsx +++ b/src/DataTable/selection/tests/ControlledSelectHeader.test.jsx @@ -42,7 +42,8 @@ describe('', () => { jest.resetAllMocks(); }); - it('correctly selects all page rows', () => { + it('correctly selects all page rows', async () => { + const user = userEvent.setup(); const isChecked = true; mockToggleAllPageRowsSelectedProps.mockReturnValue({ checked: isChecked, @@ -53,13 +54,14 @@ describe('', () => { render(); const checkbox = screen.getByRole('checkbox'); - userEvent.click(checkbox); + await user.click(checkbox); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith(rows, tableProps.itemCount); }); - it('correctly unselects all page rows', () => { + it('correctly unselects all page rows', async () => { + const user = userEvent.setup(); const spy = jest.spyOn(selectActions, 'clearPageSelectionAction'); mockToggleAllPageRowsSelectedProps.mockReturnValue({ checked: false, @@ -78,7 +80,7 @@ describe('', () => { render(); const checkbox = screen.getByRole('checkbox'); - userEvent.click(checkbox); + await user.click(checkbox); expect(spy).toHaveBeenCalledTimes(1); const rowIds = getRowIds(rows).map(id => id.toString()); diff --git a/src/DataTable/tests/DataViewToggle.test.jsx b/src/DataTable/tests/DataViewToggle.test.jsx index 8c10e83ba4..24535e8332 100644 --- a/src/DataTable/tests/DataViewToggle.test.jsx +++ b/src/DataTable/tests/DataViewToggle.test.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; import userEvent from '@testing-library/user-event'; import DataTableContext from '../DataTableContext'; @@ -78,6 +77,7 @@ describe('data view toggle behavior', () => { }); test('onDataViewToggle is invoked when clicking on buttons', async () => { + const user = userEvent.setup(); const onDataViewToggle = jest.fn(); render( { ); expect(screen.queryByRole('group')).toBeInTheDocument(); const cardButton = screen.getByLabelText(DATA_VIEW_TOGGLE_VALUES.card.alt); - await act(async () => { - userEvent.click(cardButton); - }); + await user.click(cardButton); expect(onDataViewToggle).toHaveBeenCalledWith(DATA_VIEW_TOGGLE_VALUES.card.value); const listButton = screen.getByLabelText(DATA_VIEW_TOGGLE_VALUES.list.alt); - await act(async () => { - userEvent.click(listButton); - }); + await user.click(listButton); expect(onDataViewToggle).toHaveBeenCalledWith(DATA_VIEW_TOGGLE_VALUES.list.value); }); }); diff --git a/src/Dropdown/deprecated/Dropdown.test.jsx b/src/Dropdown/deprecated/Dropdown.test.jsx index e95bbc1045..6e682c4935 100644 --- a/src/Dropdown/deprecated/Dropdown.test.jsx +++ b/src/Dropdown/deprecated/Dropdown.test.jsx @@ -62,37 +62,43 @@ describe('', () => { }); it('opens on trigger click', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); menuOpen(true, wrapper); }); it('should focus on the first item after opening', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); expect(wrapper.getByText('Google')).toHaveFocus(); }); it('does not close on click inside the menu', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); - await userEvent.click(wrapper.getByText('Google')); // Do nothing + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); + await user.click(wrapper.getByText('Google')); // Do nothing menuOpen(true, wrapper); }); it('closes on trigger click', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); // Close + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); // Close menuOpen(false, wrapper); }); it('should focus on the trigger button after closing', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); // Close + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); // Close expect(wrapper.getByRole('button', { name: 'Search Engines' })).toHaveFocus(); }); it('closes on document click when open', async () => { - await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); + const user = userEvent.setup(); + await user.click(wrapper.getByRole('button', { name: 'Search Engines' })); menuOpen(true, wrapper); - document.dispatchEvent(new MouseEvent('click')); + await user.click(document.body); menuOpen(false, wrapper); }); }); @@ -105,72 +111,82 @@ describe('', () => { }); it('opens on Enter keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); + await user.keyboard('{Enter}'); menuOpen(true, wrapper); }); it('opens on Space keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{space}'); + await user.keyboard(' '); menuOpen(true, wrapper); }); it('should focus on the first item after opening', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); + await user.keyboard('{Enter}'); expect(wrapper.getByText('Google')).toHaveFocus(); }); it('should focus the next item after ArrowDown keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); - await userEvent.keyboard('{arrowdown}'); + await user.keyboard('{Enter}'); + await user.keyboard('{arrowdown}'); expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); it('should focus the next item after Tab keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); - await userEvent.tab(); + await user.keyboard('{Enter}'); + await user.tab(); expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); it('should loop focus to the first item after Tab keyDown on last item', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); + await user.keyboard('{Enter}'); wrapper.getByRole('link', { name: 'Yahoo' }).focus(); - await userEvent.tab(); + await user.tab(); expect(wrapper.getByText('Google')).toHaveFocus(); }); it('should loop focus to the last item after ArrowUp keyDown on first item', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); + await user.keyboard('{Enter}'); wrapper.getByRole('link', { name: 'Google' }).focus(); - await userEvent.keyboard('{arrowup}'); + await user.keyboard('{arrowup}'); expect(wrapper.getByText('Yahoo')).toHaveFocus(); }); it('should focus the previous item after Shift + Tab keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); + await user.keyboard('{Enter}'); wrapper.getByRole('link', { name: 'Yahoo' }).focus(); - await userEvent.keyboard('{Shift>}{Tab}'); + await user.keyboard('{Shift>}{Tab}'); expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); it('should close the menu on Escape keyDown', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); - await userEvent.keyboard('{escape}'); + await user.keyboard('{Enter}'); + await user.keyboard('{escape}'); menuOpen(false, wrapper); }); it('should focus on the trigger button after closing', async () => { + const user = userEvent.setup(); wrapper.getByRole('button', { name: 'Search Engines' }).focus(); - await userEvent.keyboard('{Enter}'); - await userEvent.keyboard('{escape}'); + await user.keyboard('{Enter}'); + await user.keyboard('{escape}'); expect(wrapper.getByRole('button', { name: 'Search Engines' })).toHaveFocus(); }); }); diff --git a/src/Form/tests/FormCheckboxSet.test.jsx b/src/Form/tests/FormCheckboxSet.test.jsx index 393364f6e3..8409077432 100644 --- a/src/Form/tests/FormCheckboxSet.test.jsx +++ b/src/Form/tests/FormCheckboxSet.test.jsx @@ -166,7 +166,8 @@ describe('FormCheckboxSet', () => { }); }); - it('checks if onClick is called once in FormCheckboxSet', () => { + it('checks if onClick is called once in FormCheckboxSet', async () => { + const user = userEvent.setup(); const handleChange = jest.fn(); const { getByLabelText } = render( @@ -181,7 +182,7 @@ describe('FormCheckboxSet', () => { , ); - userEvent.click(getByLabelText('Red')); + await user.click(getByLabelText('Red')); expect(handleChange).toHaveBeenCalledTimes(1); }); }); diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index 3388013bd6..1e01ab8371 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -28,7 +28,8 @@ function Component({ isClearValue }) { } describe('FormControl', () => { - it('textarea changes its height with autoResize prop', () => { + it('textarea changes its height with autoResize prop', async () => { + const user = userEvent.setup(); const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref); const onChangeFunc = jest.fn(); const inputText = 'new text'; @@ -45,25 +46,27 @@ describe('FormControl', () => { expect(useReferenceSpy).toHaveBeenCalledTimes(1); expect(ref.current.style.height).toBe('0px'); - userEvent.type(textarea, inputText); + await user.type(textarea, inputText); expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length); expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`); }); - it('should apply and accept input mask for phone numbers', () => { + it('should apply and accept input mask for phone numbers', async () => { + const user = userEvent.setup(); render(); const input = screen.getByTestId('form-control-with-mask'); - userEvent.type(input, '5555555555'); + await user.type(input, '5555555555'); expect(input.value).toBe('+1 (555) 555-5555'); }); - it('should be cleared from the mask elements value', () => { + it('should be cleared from the mask elements value', async () => { + const user = userEvent.setup(); render(); const input = screen.getByTestId('form-control-with-mask'); - userEvent.type(input, '5555555555'); + await user.type(input, '5555555555'); expect(input.value).toBe('+1 (555) 555-5555'); expect(unmaskedInputValue).toBe('15555555555'); diff --git a/src/Form/tests/FormRadioSet.test.jsx b/src/Form/tests/FormRadioSet.test.jsx index 23cf96dd23..5f1e269604 100644 --- a/src/Form/tests/FormRadioSet.test.jsx +++ b/src/Form/tests/FormRadioSet.test.jsx @@ -109,7 +109,8 @@ describe('FormRadioSet', () => { expect(deciduousRadio).toHaveAttribute('name', 'trees'); }); - it('checks if onClick is called once in FormRadioSet', () => { + it('checks if onClick is called once in FormRadioSet', async () => { + const user = userEvent.setup(); const handleChange = jest.fn(); const { getByLabelText } = render( @@ -124,7 +125,7 @@ describe('FormRadioSet', () => { , ); - userEvent.click(getByLabelText('Red')); + await user.click(getByLabelText('Red')); expect(handleChange).toHaveBeenCalledTimes(1); }); }); diff --git a/src/IconButtonToggle/IconButtonToggle.test.jsx b/src/IconButtonToggle/IconButtonToggle.test.jsx index e7ef9fe6d1..1b664e44dc 100644 --- a/src/IconButtonToggle/IconButtonToggle.test.jsx +++ b/src/IconButtonToggle/IconButtonToggle.test.jsx @@ -21,7 +21,8 @@ describe('IconButtonToggle tests', () => { expect(btnAbc).toHaveClass('btn-icon-primary-active'); expect(btnAbc).toHaveAttribute('aria-selected', 'true'); }); - test('switching activeValue works as expected', () => { + test('switching activeValue works as expected', async () => { + const user = userEvent.setup(); const spyChanger = jest.fn(); render( @@ -38,7 +39,7 @@ describe('IconButtonToggle tests', () => { expect(btnAbc).toHaveClass('btn-icon-primary-active'); expect(btnAbc).toHaveAttribute('aria-selected', 'true'); - userEvent.click(btnDef); + await user.click(btnDef); waitFor(() => { expect(btnDef).toHaveClass('btn-icon-primary-active'); diff --git a/src/ListBox/ListBox.test.jsx b/src/ListBox/ListBox.test.jsx index 19da147012..c95aca44e3 100644 --- a/src/ListBox/ListBox.test.jsx +++ b/src/ListBox/ListBox.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import ListBox from '.'; @@ -82,15 +82,18 @@ describe('ListBox', () => { listBoxElement.focus(); - expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); + await waitFor(() => { + expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); + }); }); it('should not select first ListBoxOption on focus if ListBoxOption selected', async () => { + const user = userEvent.setup(); const listBoxElement = screen.getByRole('listbox'); listBoxElement.focus(); - await userEvent.keyboard('{arrowdown}'); + await user.keyboard('{arrowdown}'); listBoxElement.focus(); @@ -98,11 +101,12 @@ describe('ListBox', () => { }); it('should select next ListBoxOption on down arrow key', async () => { + const user = userEvent.setup(); const listBoxElement = screen.getByRole('listbox'); listBoxElement.focus(); - await userEvent.keyboard('{arrowdown}'); + await user.keyboard('{arrowdown}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-1'); }); diff --git a/src/Modal/tests/ModalLayer.test.tsx b/src/Modal/tests/ModalLayer.test.tsx index f316086cea..974da3a770 100644 --- a/src/Modal/tests/ModalLayer.test.tsx +++ b/src/Modal/tests/ModalLayer.test.tsx @@ -78,7 +78,8 @@ describe('', () => { }); describe('Dismiss modal', () => { - it('closes a non-blocking modal layer when backdrop is clicked', () => { + it('closes a non-blocking modal layer when backdrop is clicked', async () => { + const user = userEvent.setup(); const closeFn = jest.fn(); render( @@ -86,7 +87,7 @@ describe('', () => { , ); const backdrop = screen.getByTestId('modal-backdrop'); - userEvent.click(backdrop); + await user.click(backdrop); expect(closeFn).toHaveBeenCalled(); }); diff --git a/src/ProductTour/Checkpoint.test.jsx b/src/ProductTour/Checkpoint.test.jsx index 2ea1aabb52..dc3efe6389 100644 --- a/src/ProductTour/Checkpoint.test.jsx +++ b/src/ProductTour/Checkpoint.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; import { IntlProvider } from 'react-intl'; import * as popper from '@popperjs/core'; @@ -100,8 +100,9 @@ describe('Checkpoint', () => { }); it('end button onClick calls handleEnd', async () => { + const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); const endButton = screen.getByText('End', { selector: 'button' }); - await userEvent.click(endButton, undefined, { skipPointerEventsCheck: true }); + await user.click(endButton); expect(handleEnd).toHaveBeenCalledTimes(1); }); }); diff --git a/src/StatusAlert/StatusAlert.test.jsx b/src/StatusAlert/StatusAlert.test.jsx index 098f8305f3..76dfb55744 100644 --- a/src/StatusAlert/StatusAlert.test.jsx +++ b/src/StatusAlert/StatusAlert.test.jsx @@ -113,17 +113,21 @@ describe('', () => { }); it('does nothing on invalid keystroke q', async () => { + const user = userEvent.setup(); const closeButton = screen.getByRole('button'); expect(document.activeElement).toEqual(closeButton); closeButton.focus(); - await userEvent.keyboard('{q}'); + await user.keyboard('{q}'); expect(document.activeElement).toEqual(closeButton); }); it('does nothing on invalid keystroke + ctrl', async () => { + const user = userEvent.setup(); const closeButton = screen.getByRole('button'); expect(document.activeElement).toEqual(closeButton); - await userEvent.keyboard('{ctrl>}{tab}{/ctrl}'); + // This was '{Control>}{Tab}{/Control}' before, but that _does_ seem to be changing the focus in newer RTL/React. + // I don't think that was the point of the test though, so it's 'z' for now. + await user.keyboard('{Control>}z{/Control}'); expect(document.activeElement).toEqual(closeButton); }); }); diff --git a/src/Tabs/deprecated/Tabs.test.jsx b/src/Tabs/deprecated/Tabs.test.jsx index a6e1afc1a5..0f2953ece1 100644 --- a/src/Tabs/deprecated/Tabs.test.jsx +++ b/src/Tabs/deprecated/Tabs.test.jsx @@ -37,14 +37,16 @@ describe('', () => { }); describe('switches tab selection', () => { - it('on click', () => { + it('on click', async () => { + const user = userEvent.setup(); const { container } = render(); const tabButtons = container.querySelectorAll('button'); - tabButtons.forEach((node, i) => { - userEvent.click(node); + for (const [i, node] of tabButtons.entries()) { + // eslint-disable-next-line no-await-in-loop + await user.click(node); tabSelectedAtIndex(i, container); - }); + } }); }); });