From 71c31dcd51372610b3bbc38f60ad7f0e3660860a Mon Sep 17 00:00:00 2001 From: Kyrylo Hudym-Levkovych Date: Mon, 18 Sep 2023 11:07:40 +0300 Subject: [PATCH] refactor: replace fireEvent with userEvent where it is possible --- src/AvatarButton/AvatarButton.test.jsx | 2 +- src/CheckBox/CheckBox.test.jsx | 24 +- src/Collapsible/Collapsible.test.jsx | 57 ++-- src/ColorPicker/ColorPicker.test.jsx | 14 +- .../filters/tests/DropdownFilter.test.jsx | 47 ++-- .../tests/MultiSelectDropdownFilter.test.jsx | 31 +-- .../tests/ControlledSelectionStatus.test.jsx | 11 +- .../selection/tests/SelectionStatus.test.jsx | 11 +- src/DataTable/tests/BulkActions.test.jsx | 29 +- src/DataTable/tests/DropdownFilters.test.jsx | 9 +- src/DataTable/tests/FilterStatus.test.jsx | 7 +- src/DataTable/tests/TableActions.test.jsx | 14 +- src/DataTable/tests/TablePagination.test.jsx | 29 +- src/Dropdown/deprecated/Dropdown.test.jsx | 248 ++++++++++-------- .../__snapshots__/Dropdown.test.jsx.snap | 74 +++--- src/Dropzone/tests/UploadProgress.test.jsx | 17 +- src/Form/tests/FormCheckbox.test.jsx | 22 +- src/Form/tests/FormCheckboxSet.test.jsx | 16 +- src/Form/tests/FormControl.test.jsx | 10 +- src/Form/tests/FormRadioSet.test.jsx | 7 +- src/Form/tests/fieldUtils.test.jsx | 37 ++- src/Form/tests/useCheckboxSetValues.test.jsx | 20 +- src/Hyperlink/Hyperlink.test.jsx | 11 +- src/IconButton/IconButton.test.jsx | 13 +- src/ListBox/ListBox.test.jsx | 162 +++++------- src/ListBoxOption/ListBoxOption.test.jsx | 51 ++-- src/Menu/Menu.test.jsx | 11 +- src/Menu/MenuItem.test.jsx | 11 +- src/Menu/SelectMenu.test.jsx | 4 +- src/Modal/ModalCloseButton.test.jsx | 36 --- src/Modal/{ => tests}/AlertModal.test.jsx | 6 +- src/Modal/{ => tests}/Modal.test.jsx | 25 +- src/Modal/tests/ModalCloseButton.test.jsx | 41 +++ src/Modal/{ => tests}/ModalLayer.test.jsx | 16 +- src/Modal/{ => tests}/ModalPopup.test.jsx | 4 +- src/Modal/{ => tests}/PopperElement.test.jsx | 2 +- src/Modal/{ => tests}/Portal.test.jsx | 2 +- src/PageBanner/PageBanner.test.jsx | 5 +- src/Pagination/Pagination.test.jsx | 38 +-- src/ProductTour/Checkpoint.test.jsx | 16 +- src/ProductTour/ProductTour.test.jsx | 116 +++++--- .../RadioButtonGroup.test.jsx | 21 +- src/SearchField/SearchField.test.jsx | 57 ++-- .../__snapshots__/SearchField.test.jsx.snap | 2 +- .../tests/SelectableBox.test.jsx | 11 +- .../SelectableBoxSet.test.jsx.snap | 7 +- src/StatusAlert/StatusAlert.test.jsx | 42 +-- src/Stepper/tests/Stepper.test.jsx | 11 +- src/Table/Table.test.jsx | 25 +- src/Tabs/Tabs.test.jsx | 18 +- src/Tabs/deprecated/Tabs.test.jsx | 6 +- src/Toast/Toast.test.jsx | 18 +- src/asInput/asInput.test.jsx | 39 +-- src/hooks/tests/useToggle.test.jsx | 21 +- 54 files changed, 822 insertions(+), 762 deletions(-) delete mode 100644 src/Modal/ModalCloseButton.test.jsx rename src/Modal/{ => tests}/AlertModal.test.jsx (94%) rename src/Modal/{ => tests}/Modal.test.jsx (92%) create mode 100644 src/Modal/tests/ModalCloseButton.test.jsx rename src/Modal/{ => tests}/ModalLayer.test.jsx (84%) rename src/Modal/{ => tests}/ModalPopup.test.jsx (97%) rename src/Modal/{ => tests}/PopperElement.test.jsx (96%) rename src/Modal/{ => tests}/Portal.test.jsx (97%) diff --git a/src/AvatarButton/AvatarButton.test.jsx b/src/AvatarButton/AvatarButton.test.jsx index 4437d8d2e7..4c743dd99f 100644 --- a/src/AvatarButton/AvatarButton.test.jsx +++ b/src/AvatarButton/AvatarButton.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; import renderer from 'react-test-renderer'; -import AvatarButton from './index'; +import AvatarButton from '.'; describe('AvatarButton', () => { it('renders in all sizes', () => { diff --git a/src/CheckBox/CheckBox.test.jsx b/src/CheckBox/CheckBox.test.jsx index 8ddff49470..fa896ba68a 100644 --- a/src/CheckBox/CheckBox.test.jsx +++ b/src/CheckBox/CheckBox.test.jsx @@ -1,5 +1,7 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + import CheckBox from '.'; describe('', () => { @@ -12,44 +14,44 @@ describe('', () => { expect(checkbox).toHaveAttribute('aria-checked', 'false'); }); - it('aria-label changes after click', () => { + it('aria-label changes after click', async () => { render(); const checkbox = screen.getByLabelText('check me out!'); expect(checkbox).toHaveAttribute('aria-checked', 'false'); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(checkbox).toHaveAttribute('aria-checked', 'true'); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(checkbox).toHaveAttribute('aria-checked', 'false'); }); - it('check that callback function is triggered when clicked', () => { + it('check that callback function is triggered when clicked', async () => { const onChangeSpy = jest.fn(); render(); const checkbox = screen.getByLabelText('check me out!'); expect(onChangeSpy).toHaveBeenCalledTimes(0); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(onChangeSpy).toHaveBeenCalledTimes(1); expect(onChangeSpy).toHaveBeenCalledWith(true, 'checkbox'); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(onChangeSpy).toHaveBeenCalledTimes(2); expect(onChangeSpy).toHaveBeenCalledWith(false, 'checkbox'); }); - it('checks if start state can be set to checked', () => { + it('checks if start state can be set to checked', async () => { render(); const checkbox = screen.getByLabelText('I start checked'); expect(checkbox).toBeChecked(); expect(checkbox).toHaveAttribute('aria-checked', 'true'); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(checkbox).not.toBeChecked(); expect(checkbox).toHaveAttribute('aria-checked', 'false'); }); - it('checkbox can be disabled', () => { + it('checkbox can be disabled', async () => { render(); const checkbox = screen.getByLabelText('I am disabled'); expect(checkbox).toBeDisabled(); - fireEvent.click(checkbox); + await userEvent.click(checkbox); expect(checkbox).toBeDisabled(); }); diff --git a/src/Collapsible/Collapsible.test.jsx b/src/Collapsible/Collapsible.test.jsx index 8258fff221..f4fbd3634a 100644 --- a/src/Collapsible/Collapsible.test.jsx +++ b/src/Collapsible/Collapsible.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import renderer from 'react-test-renderer'; +import userEvent from '@testing-library/user-event'; import Collapsible from '.'; @@ -118,40 +119,40 @@ describe('', () => { collapsible = ref.current; }); - it('opens on trigger click', () => { + it('opens on trigger click', async () => { expect(screen.getAllByRole('button')[0]).toBeInTheDocument(); - fireEvent.click(screen.getAllByRole('button')[0]); // Open + await userEvent.click(screen.getAllByRole('button')[0]); // Open expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); - it('closes on trigger click', () => { + it('closes on trigger click', async () => { collapsible.open(); expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); - fireEvent.click(screen.getAllByRole('button')[0]); // Close + await userEvent.click(screen.getAllByRole('button')[0]); // Close expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('does not open on close only trigger click', () => { + it('does not open on close only trigger click', async () => { collapsible.close(); - fireEvent.click(screen.getByTestId('close-only')); // No-op + await userEvent.click(screen.getByTestId('close-only')); // No-op expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('closes on close only trigger click', () => { + it('closes on close only trigger click', async () => { collapsible.open(); - fireEvent.click(screen.getByTestId('close-only')); // Close + await userEvent.click(screen.getByTestId('close-only')); // Close expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('does not close on open only trigger click', () => { + it('does not close on open only trigger click', async () => { collapsible.open(); - fireEvent.click(screen.getByTestId('open-only')); // No-op + await userEvent.click(screen.getByTestId('open-only')); // No-op expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); - it('opens on open only trigger click', () => { + it('opens on open only trigger click', async () => { collapsible.close(); - fireEvent.click(screen.getByTestId('open-only')); // Open + await userEvent.click(screen.getByTestId('open-only')); // Open expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); }); @@ -166,38 +167,44 @@ describe('', () => { collapsible = ref.current; }); - it('opens on trigger enter keydown', () => { - fireEvent.keyDown(screen.getAllByRole('button')[0], { key: 'Enter' }); // Open + it('opens on trigger enter keydown', async () => { + screen.getAllByRole('button')[0].focus(); + await userEvent.keyboard('{enter}'); // Open expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); - it('closes on trigger enter keydown', () => { + it('closes on trigger enter keydown', async () => { collapsible.open(); - fireEvent.keyDown(screen.getAllByRole('button')[0], { key: 'Enter' }); // Close + screen.getAllByRole('button')[0].focus(); + await userEvent.keyboard('{enter}'); // Close expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('does not open on close only trigger enter keydown', () => { + it('does not open on close only trigger enter keydown', async () => { collapsible.close(); - fireEvent.keyDown(screen.getByTestId('close-only'), { key: 'Enter' }); // No-op + screen.getByTestId('close-only').focus(); + await userEvent.keyboard('{enter}'); // No-op expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('closes on close only trigger enter keydown', () => { + it('closes on close only trigger enter keydown', async () => { collapsible.open(); - fireEvent.keyDown(screen.getByTestId('close-only'), { key: 'Enter' }); // Close + screen.getByTestId('close-only').focus(); + await userEvent.keyboard('{enter}'); // Close expect(screen.queryByText(EXAMPLE_CONTENT)).not.toBeInTheDocument(); }); - it('does not close on open only trigger enter keydown', () => { + it('does not close on open only trigger enter keydown', async () => { collapsible.open(); - fireEvent.keyDown(screen.getByTestId('open-only'), { key: 'Enter' }); // No-op + screen.getByTestId('open-only').focus(); + await userEvent.keyboard('{enter}'); // No-op expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); - it('opens on open only trigger enter keydown', () => { + it('opens on open only trigger enter keydown', async () => { collapsible.close(); - fireEvent.keyDown(screen.getByTestId('open-only'), { key: 'Enter' }); // Open + screen.getByTestId('open-only').focus(); + await userEvent.keyboard('{enter}'); // Open expect(screen.getByText(EXAMPLE_CONTENT)).toBeInTheDocument(); }); }); diff --git a/src/ColorPicker/ColorPicker.test.jsx b/src/ColorPicker/ColorPicker.test.jsx index a02d055a4d..60c38cdac3 100644 --- a/src/ColorPicker/ColorPicker.test.jsx +++ b/src/ColorPicker/ColorPicker.test.jsx @@ -1,8 +1,8 @@ import React from 'react'; import renderer from 'react-test-renderer'; import userEvent from '@testing-library/user-event'; -import { render, fireEvent, screen } from '@testing-library/react'; -import { act } from 'react-dom/test-utils'; +import { render, screen } from '@testing-library/react'; + import ColorPicker from '.'; describe('renders correctly', () => { @@ -29,13 +29,11 @@ describe('picker works as expected', () => { const color = 'wassap'; const setColor = jest.fn(); it('validates hex color', async () => { - render(); - await act(async () => { - userEvent.click(screen.getByRole('button')); - }); + const { rerender } = render(); + await userEvent.click(screen.getByRole('button')); expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument(); - const input = screen.getByTestId('hex-input'); - fireEvent.change(input, { target: { value: '#32116c' } }); + + rerender(); expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument(); }); }); diff --git a/src/DataTable/filters/tests/DropdownFilter.test.jsx b/src/DataTable/filters/tests/DropdownFilter.test.jsx index 3ae499c46f..95acb02ebb 100644 --- a/src/DataTable/filters/tests/DropdownFilter.test.jsx +++ b/src/DataTable/filters/tests/DropdownFilter.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import DropdownFilter from '../DropdownFilter'; @@ -26,43 +27,43 @@ describe('', () => { }); it('renders a select button', () => { - const { getByLabelText } = render(); - expect(getByLabelText(props.column.Header)).toBeInTheDocument(); + render(); + expect(screen.getByLabelText(props.column.Header)).toBeInTheDocument(); }); - it('sets a filter - no initial filters', () => { - const { getByLabelText } = render(); - const select = getByLabelText(props.column.Header); - fireEvent.click(select); - fireEvent.change(select, { target: { value: palomino.value } }); + it('sets a filter - no initial filters', async () => { + render(); + const select = screen.getByLabelText(props.column.Header); + await userEvent.click(select); + await userEvent.selectOptions(select, palomino.value); expect(setFilterMock).toHaveBeenCalledWith(palomino.value); }); - it('sets a filter - initial filters', () => { - const { getByLabelText } = render( + it('sets a filter - initial filters', async () => { + render( , ); - const select = getByLabelText(props.column.Header); - fireEvent.click(select); - fireEvent.change(select, { target: { value: palomino.value } }); + const select = screen.getByLabelText(props.column.Header); + await userEvent.click(select); + await userEvent.selectOptions(select, palomino.value); expect(setFilterMock).toHaveBeenCalledWith(palomino.value); }); - it('removes filters when default option is clicked', () => { - const { getByLabelText } = render( + it('removes filters when default option is clicked', async () => { + render( , ); - const select = getByLabelText(props.column.Header); - fireEvent.click(select); - fireEvent.change(select, { target: { value: '' } }); + const select = screen.getByLabelText(props.column.Header); + await userEvent.click(select); + await userEvent.selectOptions(select, ''); expect(setFilterMock).toHaveBeenCalledWith(undefined); }); - it('displays a number if a number is provided', () => { - const { getByLabelText, getByText } = render(); - const select = getByLabelText(props.column.Header); - fireEvent.click(select); - const option = getByText(`${roan.name} (${roan.number})`); + it('displays a number if a number is provided', async () => { + render(); + const select = screen.getByLabelText(props.column.Header); + await userEvent.click(select); + const option = screen.getByText(`${roan.name} (${roan.number})`); expect(option).toBeInTheDocument(); }); }); diff --git a/src/DataTable/filters/tests/MultiSelectDropdownFilter.test.jsx b/src/DataTable/filters/tests/MultiSelectDropdownFilter.test.jsx index ba778af3bb..dd620cd5f8 100644 --- a/src/DataTable/filters/tests/MultiSelectDropdownFilter.test.jsx +++ b/src/DataTable/filters/tests/MultiSelectDropdownFilter.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { - render, fireEvent, screen, act, -} from '@testing-library/react'; +import { render, screen, act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import MultiSelectDropdownFilter from '../MultiSelectDropdownFilter'; @@ -28,7 +27,7 @@ describe('', () => { }); it('renders a list of checkboxes', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); await act(async () => { const checkboxes = screen.getAllByRole('checkbox'); expect(checkboxes.length).toEqual(3); @@ -40,34 +39,28 @@ describe('', () => { }); it('sets a filter - no initial filters', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); const checkbox = screen.getAllByRole('checkbox')[1]; - await act(async () => { - fireEvent.click(checkbox); - }); + await userEvent.click(checkbox, undefined, { skipPointerEventsCheck: true }); expect(setFilterMock).toHaveBeenCalledWith([palomino.value]); }); it('sets a filter - initial filters', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); const checkbox = screen.getAllByRole('checkbox')[1]; - await act(async () => { - fireEvent.click(checkbox); - }); + await userEvent.click(checkbox, undefined, { skipPointerEventsCheck: true }); expect(setFilterMock).toHaveBeenCalledWith([roan.value, palomino.value]); }); it('removes a filter', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); const checkbox = screen.getAllByRole('checkbox')[1]; - await act(async () => { - fireEvent.click(checkbox); - }); + await userEvent.click(checkbox, undefined, { skipPointerEventsCheck: true }); expect(setFilterMock).toHaveBeenCalledWith([]); }); it('renders checkbox label with filter name', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); await act(async () => { const label = screen.getByText(roan.name); expect(label).toBeInTheDocument(); @@ -75,7 +68,7 @@ describe('', () => { }); it('renders checkbox label with number - with badge', async () => { render(); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); await act(async () => { const label = screen.getByText(roan.name); expect(label).toBeInTheDocument(); @@ -87,7 +80,7 @@ describe('', () => { render( , ); - fireEvent.click(screen.getByText(props.column.Header)); + await userEvent.click(screen.getByText(props.column.Header)); await act(async () => { const label = screen.getByText(palomino.name); expect(label).toBeInTheDocument(); diff --git a/src/DataTable/selection/tests/ControlledSelectionStatus.test.jsx b/src/DataTable/selection/tests/ControlledSelectionStatus.test.jsx index f671faeb43..e7850350ef 100644 --- a/src/DataTable/selection/tests/ControlledSelectionStatus.test.jsx +++ b/src/DataTable/selection/tests/ControlledSelectionStatus.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; +import userEvent from '@testing-library/user-event'; import ControlledSelectionStatus from '../ControlledSelectionStatus'; import { clearSelectionAction, setSelectAllRowsAllPagesAction, setSelectedRowsAction } from '../data/actions'; @@ -132,7 +133,7 @@ describe('', () => { expect(screen.queryByText(CLEAR_SELECTION_TEXT)).not.toBeInTheDocument(); }); - it('toggles select all on select all button click', () => { + it('toggles select all on select all button click', async () => { const dispatchSpy = jest.fn(); render( ', () => { />, ); const selectAllButton = screen.getByTestId(SELECT_ALL_TEST_ID); - fireEvent.click(selectAllButton); + await userEvent.click(selectAllButton); expect(dispatchSpy).toHaveBeenCalledTimes(1); const action = setSelectAllRowsAllPagesAction(); expect(dispatchSpy).toHaveBeenCalledWith(action); }); - it('clears selection on clear selection button click', () => { + it('clears selection on clear selection button click', async () => { const dispatchSpy = jest.fn(); render( ', () => { />, ); const clearSelectionButton = screen.getByTestId(CLEAR_SELECTION_TEST_ID); - fireEvent.click(clearSelectionButton); + await userEvent.click(clearSelectionButton); expect(dispatchSpy).toHaveBeenCalledTimes(1); const action = clearSelectionAction(); expect(dispatchSpy).toHaveBeenCalledWith(action); diff --git a/src/DataTable/selection/tests/SelectionStatus.test.jsx b/src/DataTable/selection/tests/SelectionStatus.test.jsx index 5aaf66b396..feb56ecf12 100644 --- a/src/DataTable/selection/tests/SelectionStatus.test.jsx +++ b/src/DataTable/selection/tests/SelectionStatus.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; +import userEvent from '@testing-library/user-event'; import SelectionStatus from '../SelectionStatus'; import DataTableContext from '../../DataTableContext'; @@ -62,7 +63,7 @@ describe('', () => { expect(selectAllButton).not.toBeInTheDocument(); }); - it('toggles select all on select all button click', () => { + it('toggles select all on select all button click', async () => { const toggleAllRowsSpy = jest.fn(); render( ', () => { />, ); const selectAllButton = screen.getByTestId(SELECT_ALL_TEST_ID); - fireEvent.click(selectAllButton); + await userEvent.click(selectAllButton); expect(toggleAllRowsSpy).toHaveBeenCalledTimes(1); expect(toggleAllRowsSpy).toHaveBeenCalledWith(true); }); @@ -102,13 +103,13 @@ describe('', () => { expect(screen.queryByTestId(CLEAR_SELECTION_TEST_ID)).not.toBeInTheDocument(); }); - it('toggles select all on clear all button click', () => { + it('toggles select all on clear all button click', async () => { const toggleAllRowsSpy = jest.fn(); render( , ); const clearSelectionButton = screen.getByTestId(CLEAR_SELECTION_TEST_ID); - fireEvent.click(clearSelectionButton); + await userEvent.click(clearSelectionButton); expect(toggleAllRowsSpy).toHaveBeenCalledTimes(1); expect(toggleAllRowsSpy).toHaveBeenCalledWith(false); }); diff --git a/src/DataTable/tests/BulkActions.test.jsx b/src/DataTable/tests/BulkActions.test.jsx index 3c8ced3e4a..392f15a6b9 100644 --- a/src/DataTable/tests/BulkActions.test.jsx +++ b/src/DataTable/tests/BulkActions.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { screen, render, fireEvent } from '@testing-library/react'; +import { screen, render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import classNames from 'classnames'; @@ -143,7 +144,7 @@ describe('', () => { const button = screen.getByText(FIRST_ACTION); expect(button).toBeInTheDocument(); }); - it('handles action on click with full table selection (all rows across all pages)', () => { + it('handles action on click with full table selection (all rows across all pages)', async () => { const onClickSpy = jest.fn(); render( ', () => { />, ); const button = screen.getAllByRole('button')[1]; - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); }); describe('two actions on click', () => { - it('performs the primary button action on click', () => { + it('performs the primary button action on click', async () => { const onClickSpy = jest.fn(); render( ', () => { />, ); const button = screen.getAllByRole('button')[1]; - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); - it('performs the second button action on click', () => { + it('performs the second button action on click', async () => { const onClickSpy = jest.fn(); render( ', () => { />, ); const button = screen.getAllByRole('button')[0]; - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); }); @@ -209,7 +210,7 @@ describe('', () => { describe('overflow menu', () => { const onClickSpy = jest.fn(); const itemTestId = 'itemTestId'; - beforeEach(() => { + beforeEach(async () => { render( ', () => { />, ); // the overflow toggle button is the first button - fireEvent.click(screen.getByRole('button', { name: ACTION_OVERFLOW_BUTTON_TEXT })); + await userEvent.click(screen.getByRole('button', { name: ACTION_OVERFLOW_BUTTON_TEXT })); }); afterEach(() => { onClickSpy.mockClear(); }); - it('displays additional actions in a ModalPopup', () => { + it('displays additional actions in a ModalPopup', async () => { const actionItems = screen.getAllByRole('button'); // subtract two for the two main buttons that aren't in the overflow menu expect(actionItems.length).toEqual(4); }); - it('performs actions when overflow items are clicked', () => { + it('performs actions when overflow items are clicked', async () => { const item = screen.getByTestId(itemTestId); - fireEvent.click(item); + await userEvent.click(item); expect(onClickSpy).toHaveBeenCalledTimes(1); }); it('passes the class names to the dropdown item', () => { @@ -243,13 +244,13 @@ describe('', () => { describe('small screen', () => { const actions = [[[]], [[, ]], [instance.bulkActions]]; - test.each(actions)('puts all actions in a dropdown %#', (testActions) => { + test.each(actions)('puts all actions in a dropdown %#', async (testActions) => { useWindowSize.mockReturnValue({ width: 500 }); const { container } = render(); const button = screen.getByRole('button', { name: SMALL_SCREEN_ACTION_OVERFLOW_BUTTON_TEXT }); expect(button).toBeInTheDocument(); expect(container.textContent).not.toContain(FIRST_ACTION); - fireEvent.click(button); + await userEvent.click(button); expect(container.textContent.length).toBeGreaterThan(0); }); it('renders the correct alt text for the dropdown', () => { diff --git a/src/DataTable/tests/DropdownFilters.test.jsx b/src/DataTable/tests/DropdownFilters.test.jsx index 1ff95a2a2b..b48e443bba 100644 --- a/src/DataTable/tests/DropdownFilters.test.jsx +++ b/src/DataTable/tests/DropdownFilters.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import DropdownFilters from '../DropdownFilters'; import { useWindowSize } from '../..'; @@ -56,7 +57,7 @@ describe('', () => { // clicking the button. expect(screen.queryByText('Occupation filter')).toBeNull(); const filtersButton = screen.getByRole('button', { name: /Filters/i }); - await fireEvent.click(filtersButton); + await userEvent.click(filtersButton); expect(screen.getByText('Occupation filter')).toBeInTheDocument(); }); @@ -65,7 +66,7 @@ describe('', () => { render(); expect(screen.queryByText('DOB filter')).toBeNull(); const filtersButton = screen.getByRole('button', { name: /Filters/i }); - fireEvent.click(filtersButton); + await userEvent.click(filtersButton); expect(screen.queryByText('DOB filter')).toBeNull(); }); @@ -88,7 +89,7 @@ describe('', () => { useWindowSize.mockReturnValue({ width: 500 }); render(); const filtersButton = screen.getByRole('button', { name: /Filters/i }); - fireEvent.click(filtersButton); + await userEvent.click(filtersButton); expect(screen.getByText('Bears filter')).toBeInTheDocument(); expect(screen.getByText('Occupation filter')).toBeInTheDocument(); }); diff --git a/src/DataTable/tests/FilterStatus.test.jsx b/src/DataTable/tests/FilterStatus.test.jsx index 9923af4c81..5a0ef41f63 100644 --- a/src/DataTable/tests/FilterStatus.test.jsx +++ b/src/DataTable/tests/FilterStatus.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; +import userEvent from '@testing-library/user-event'; import FilterStatus from '../FilterStatus'; import DataTableContext from '../DataTableContext'; @@ -40,13 +41,13 @@ describe('', () => { const button = screen.getByText(filterProps.clearFiltersText); expect(button).toHaveClass(filterProps.buttonClassName); }); - it('clears the selection on click', () => { + it('clears the selection on click', async () => { const clearSpy = jest.fn(); render( , ); const button = screen.getByText(filterProps.clearFiltersText); - fireEvent.click(button); + await userEvent.click(button); expect(clearSpy).toHaveBeenCalledTimes(1); expect(clearSpy).toHaveBeenCalledWith([]); }); diff --git a/src/DataTable/tests/TableActions.test.jsx b/src/DataTable/tests/TableActions.test.jsx index 7b5b6882b5..5c17cb14e8 100644 --- a/src/DataTable/tests/TableActions.test.jsx +++ b/src/DataTable/tests/TableActions.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import classNames from 'classnames'; import TableActions from '../TableActions'; @@ -98,12 +98,12 @@ describe('', () => { }); describe('with one action', () => { - it('performs the button action on click', () => { + it('performs the button action on click', async () => { const onClickSpy = jest.fn(); const tableInstance = { ...instance, tableActions: [] }; render(); const button = screen.getByText('First Action'); - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); }); @@ -131,21 +131,21 @@ describe('', () => { }); describe('two actions on click', () => { - it('performs the primary button action on click', () => { + it('performs the primary button action on click', async () => { const onClickSpy = jest.fn(); const tableInstance = { ...instance, tableActions: [, ] }; render(); const button = screen.getByText('First Action'); - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); - it('performs the second button action on click', () => { + it('performs the second button action on click', async () => { const onClickSpy = jest.fn(); const tableInstance = { ...instance, tableActions: [, ] }; render(); const button = screen.getByText('Second Action'); - fireEvent.click(button); + await userEvent.click(button); expect(onClickSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/DataTable/tests/TablePagination.test.jsx b/src/DataTable/tests/TablePagination.test.jsx index e4922d8409..0131ae101d 100644 --- a/src/DataTable/tests/TablePagination.test.jsx +++ b/src/DataTable/tests/TablePagination.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import TablePagination from '../TablePagination'; import DataTableContext from '../DataTableContext'; @@ -25,19 +26,21 @@ describe('', () => { expect(container.textContent).toBe(''); }); - it('Shows dropdown button with the page count as label and performs actions when dropdown items are clicked', () => { - const { getAllByTestId, getByRole } = render(); - const dropdownButton = getByRole('button', { name: /2 of 3/i }); - expect(dropdownButton).toBeInTheDocument(); + it( + 'Shows dropdown button with the page count as label and performs actions when dropdown items are clicked', + async () => { + const { getAllByTestId, getByRole } = render(); + const dropdownButton = getByRole('button', { name: /2 of 3/i }); + expect(dropdownButton).toBeInTheDocument(); - fireEvent.click(dropdownButton); + await userEvent.click(dropdownButton); - const dropdownChoices = getAllByTestId('pagination-dropdown-item'); - expect(dropdownChoices.length).toEqual(instance.pageCount); + const dropdownChoices = getAllByTestId('pagination-dropdown-item'); + expect(dropdownChoices.length).toEqual(instance.pageCount); + await userEvent.click(dropdownChoices[1], undefined, { skipPointerEventsCheck: true }); - fireEvent.click(dropdownChoices[1]); - - expect(instance.gotoPage).toHaveBeenCalledTimes(1); - expect(instance.gotoPage).toHaveBeenCalledWith(1); - }); + expect(instance.gotoPage).toHaveBeenCalledTimes(1); + expect(instance.gotoPage).toHaveBeenCalledWith(1); + }, + ); }); diff --git a/src/Dropdown/deprecated/Dropdown.test.jsx b/src/Dropdown/deprecated/Dropdown.test.jsx index da4bb6d769..e95bbc1045 100644 --- a/src/Dropdown/deprecated/Dropdown.test.jsx +++ b/src/Dropdown/deprecated/Dropdown.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import renderer from 'react-test-renderer'; +import userEvent from '@testing-library/user-event'; import Dropdown from './index'; import Icon from '../../Icon'; @@ -19,9 +20,8 @@ const menuContent = ( ); const menuOpen = (isOpen, wrapper) => { - expect(wrapper.find('.dropdown').hasClass('show')).toEqual(isOpen); - expect(wrapper.find('button').prop('aria-expanded')).toEqual(isOpen); - expect(wrapper.find('[aria-hidden=false]').exists()).toEqual(isOpen); + expect(wrapper.container.querySelector('.dropdown').classList.contains('show')).toBe(isOpen); + expect(wrapper.getByRole('button', { name: 'Search Engines' })).toHaveAttribute('aria-expanded', isOpen ? 'true' : 'false'); }; describe('', () => { @@ -55,160 +55,184 @@ describe('', () => { }); describe('Mouse Interactions', () => { - const app = document.createElement('div'); - document.body.appendChild(app); + let wrapper; - const wrapper = mount({menuContent}, { attachTo: app }); - const menuTrigger = wrapper.find('button'); - const menuContainer = wrapper.find('.dropdown-menu'); - const menuItems = wrapper.find('.dropdown-menu a'); + beforeEach(() => { + wrapper = render({menuContent}); + }); - it('opens on trigger click', () => { - menuTrigger.simulate('click'); // Open + it('opens on trigger click', async () => { + await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); menuOpen(true, wrapper); }); - it('should focus on the first item after opening', () => { - expect(menuItems.first().is(':focus')).toBe(true); + it('should focus on the first item after opening', async () => { + await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); + expect(wrapper.getByText('Google')).toHaveFocus(); }); - it('does not close on click inside the menu', () => { - menuContainer.simulate('click'); // Do nothing + 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 menuOpen(true, wrapper); }); - it('closes on trigger click', () => { - menuTrigger.simulate('click'); // Close + 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 menuOpen(false, wrapper); }); - it('should focus on the trigger button after closing', () => { - expect(menuTrigger.is(':focus')).toBe(true); + 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 + expect(wrapper.getByRole('button', { name: 'Search Engines' })).toHaveFocus(); }); - it('closes on document click when open', () => { - menuTrigger.simulate('click'); // Open + it('closes on document click when open', async () => { + await userEvent.click(wrapper.getByRole('button', { name: 'Search Engines' })); menuOpen(true, wrapper); document.dispatchEvent(new MouseEvent('click')); - wrapper.update(); // Let react re-render menuOpen(false, wrapper); }); }); describe('Keyboard Interactions', () => { - // Note: menuContent has three items - const app = document.createElement('div'); - document.body.appendChild(app); + let wrapper; + + beforeEach(() => { + wrapper = render({menuContent}); + }); - const wrapper = mount({menuContent}, { attachTo: app }); - const menuTrigger = wrapper.find('button'); - const menuContainer = wrapper.find('.dropdown-menu'); - const menuItems = wrapper.find('.dropdown-menu a'); + it('opens on Enter keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + menuOpen(true, wrapper); + }); - it('opens on click', () => { - menuTrigger.simulate('click'); // Open + it('opens on Space keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{space}'); menuOpen(true, wrapper); }); - it('should focus on the first item after opening', () => { - expect(menuItems.first().is(':focus')).toBe(true); + it('should focus on the first item after opening', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + expect(wrapper.getByText('Google')).toHaveFocus(); }); - it('should focus the next item after ArrowDown keyDown', () => { - menuContainer.simulate('keyDown', { key: 'ArrowDown' }); - expect(menuItems.at(1).is(':focus')).toBe(true); + it('should focus the next item after ArrowDown keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + await userEvent.keyboard('{arrowdown}'); + expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); - it('should focus the next item after Tab keyDown', () => { - menuContainer.simulate('keyDown', { key: 'Tab' }); - expect(menuItems.at(2).is(':focus')).toBe(true); + it('should focus the next item after Tab keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + await userEvent.tab(); + expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); - it('should loop focus to the first item after Tab keyDown on last item', () => { - menuContainer.simulate('keyDown', { key: 'Tab' }); - expect(menuItems.at(0).is(':focus')).toBe(true); + it('should loop focus to the first item after Tab keyDown on last item', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + wrapper.getByRole('link', { name: 'Yahoo' }).focus(); + await userEvent.tab(); + expect(wrapper.getByText('Google')).toHaveFocus(); }); - it('should loop focus to the last item after ArrowUp keyDown on first item', () => { - menuContainer.simulate('keyDown', { key: 'ArrowUp' }); - expect(menuItems.at(2).is(':focus')).toBe(true); + it('should loop focus to the last item after ArrowUp keyDown on first item', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + wrapper.getByRole('link', { name: 'Google' }).focus(); + await userEvent.keyboard('{arrowup}'); + expect(wrapper.getByText('Yahoo')).toHaveFocus(); }); - it('should focus the previous item after Shift + Tab keyDown', () => { - menuContainer.simulate('keyDown', { key: 'Tab', shiftKey: true }); - expect(menuItems.at(1).is(':focus')).toBe(true); + it('should focus the previous item after Shift + Tab keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + wrapper.getByRole('link', { name: 'Yahoo' }).focus(); + await userEvent.keyboard('{Shift>}{Tab}'); + expect(wrapper.getByText('DuckDuckGo')).toHaveFocus(); }); - it('should close the menu on Escape keyDown', () => { - menuContainer.simulate('keyDown', { key: 'Escape' }); + it('should close the menu on Escape keyDown', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + await userEvent.keyboard('{escape}'); menuOpen(false, wrapper); }); - it('should focus on the trigger button after closing', () => { - expect(menuTrigger.is(':focus')).toBe(true); + it('should focus on the trigger button after closing', async () => { + wrapper.getByRole('button', { name: 'Search Engines' }).focus(); + await userEvent.keyboard('{Enter}'); + await userEvent.keyboard('{escape}'); + expect(wrapper.getByRole('button', { name: 'Search Engines' })).toHaveFocus(); }); }); - describe('Backwards compatibility', () => { - it('renders the basic usage', () => { - const tree = renderer.create(( - - )).toJSON(); - expect(tree).toMatchSnapshot(); - }); + it('renders the basic usage', () => { + const tree = renderer.create(( + + )).toJSON(); + expect(tree).toMatchSnapshot(); + }); - it('renders menu items as elements', () => { - const tree = renderer.create(( - Google, - DuckDuckGo, - Yahoo, - ]} - /> - )).toJSON(); - expect(tree).toMatchSnapshot(); - }); + it('renders menu items as elements', () => { + const tree = renderer.create(( + Google, + DuckDuckGo, + Yahoo, + ]} + /> + )).toJSON(); + expect(tree).toMatchSnapshot(); + }); - it('renders with icon element', () => { - const tree = renderer.create(( - } - menuItems={[ - { - label: 'Google', - href: 'https://google.com', - }, - { - label: 'DuckDuckGo', - href: 'https://duckduckgo.com', - }, - { - label: 'Yahoo', - href: 'https://yahoo.com', - }, - ]} - /> - )).toJSON(); - expect(tree).toMatchSnapshot(); - }); + it('renders with icon element', () => { + const tree = renderer.create(( + } + menuItems={[ + { + label: 'Google', + href: 'https://google.com', + }, + { + label: 'DuckDuckGo', + href: 'https://duckduckgo.com', + }, + { + label: 'Yahoo', + href: 'https://yahoo.com', + }, + ]} + /> + )).toJSON(); + expect(tree).toMatchSnapshot(); }); }); diff --git a/src/Dropdown/deprecated/__snapshots__/Dropdown.test.jsx.snap b/src/Dropdown/deprecated/__snapshots__/Dropdown.test.jsx.snap index 5e374c6e7a..1a3ebf5bab 100644 --- a/src/Dropdown/deprecated/__snapshots__/Dropdown.test.jsx.snap +++ b/src/Dropdown/deprecated/__snapshots__/Dropdown.test.jsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` Backwards compatibility renders menu items as elements 1`] = ` +exports[` Rendering renders the happy path 1`] = `
@@ -8,7 +8,7 @@ exports[` Backwards compatibility renders menu items as elements 1`] aria-expanded={false} aria-haspopup={true} className="dropdown-toggle btn btn-light" - id="pgn__dropdown-trigger-19" + id="pgn__dropdown-trigger-0" onClick={[Function]} type="button" > @@ -16,26 +16,26 @@ exports[` Backwards compatibility renders menu items as elements 1`]
Google DuckDuckGo Yahoo @@ -43,7 +43,7 @@ exports[` Backwards compatibility renders menu items as elements 1`]
`; -exports[` Backwards compatibility renders the basic usage 1`] = ` +exports[` Rendering renders when there is html content in the trigger button 1`] = `
@@ -51,7 +51,7 @@ exports[` Backwards compatibility renders the basic usage 1`] = ` aria-expanded={false} aria-haspopup={true} className="dropdown-toggle btn btn-light" - id="pgn__dropdown-trigger-18" + id="pgn__dropdown-trigger-1" onClick={[Function]} type="button" > @@ -59,7 +59,7 @@ exports[` Backwards compatibility renders the basic usage 1`] = `
Backwards compatibility renders the basic usage 1`] = `
`; -exports[` Backwards compatibility renders with icon element 1`] = ` +exports[` Rendering renders with custom menu content 1`] = ` +
+ Custom Content +
+`; + +exports[` renders menu items as elements 1`] = `
@@ -98,11 +106,6 @@ exports[` Backwards compatibility renders with icon element 1`] = ` onClick={[Function]} type="button" > - Search Engines
Backwards compatibility renders with icon element 1`] = ` > Google DuckDuckGo Yahoo @@ -134,7 +137,7 @@ exports[` Backwards compatibility renders with icon element 1`] = `
`; -exports[` Rendering renders the happy path 1`] = ` +exports[` renders the basic usage 1`] = `
@@ -142,8 +145,7 @@ exports[` Rendering renders the happy path 1`] = ` aria-expanded={false} aria-haspopup={true} className="dropdown-toggle btn btn-light" - data-testid="menu-container" - id="pgn__dropdown-trigger-0" + id="pgn__dropdown-trigger-19" onClick={[Function]} type="button" > @@ -151,29 +153,25 @@ exports[` Rendering renders the happy path 1`] = ` `; -exports[` Rendering renders when there is html content in the trigger button 1`] = ` +exports[` renders with icon element 1`] = ` `; - -exports[` Rendering renders with custom menu content 1`] = ` -
- Custom Content -
-`; diff --git a/src/Dropzone/tests/UploadProgress.test.jsx b/src/Dropzone/tests/UploadProgress.test.jsx index 7798af804e..7dbd3e72f0 100644 --- a/src/Dropzone/tests/UploadProgress.test.jsx +++ b/src/Dropzone/tests/UploadProgress.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; +import userEvent from '@testing-library/user-event'; import UploadProgress from '../UploadProgress'; @@ -26,22 +27,22 @@ function UploadProgressWrapper({ children, ...props }) { describe('', () => { it('renders spinner if receives "spinner" as a variant prop', () => { - const { getByTestId } = render(); - const spinner = getByTestId('upload-spinner'); + render(); + const spinner = screen.getByTestId('upload-spinner'); expect(spinner).toBeInTheDocument(); expect(spinner).toHaveTextContent(`Uploading ${defaultProps.name}, ${defaultProps.percent}% done.`); }); - it('renders progress bar if receives "bar" as a variant prop', () => { - const { getByTestId, getByText } = render(); - const progressBar = getByTestId('upload-progress-bar'); + it('renders progress bar if receives "bar" as a variant prop', async () => { + render(); + const progressBar = screen.getByTestId('upload-progress-bar'); expect(progressBar).toBeInTheDocument(); expect(progressBar).toHaveTextContent(`${defaultProps.percent}%`); - const cancelButton = getByText('Cancel'); + const cancelButton = screen.getByText('Cancel'); expect(cancelButton).toBeInTheDocument(); - fireEvent.click(cancelButton); + await userEvent.click(cancelButton); expect(onCancel).toHaveBeenCalledTimes(1); }); }); diff --git a/src/Form/tests/FormCheckbox.test.jsx b/src/Form/tests/FormCheckbox.test.jsx index 5b00dafcd4..bcd133bc36 100644 --- a/src/Form/tests/FormCheckbox.test.jsx +++ b/src/Form/tests/FormCheckbox.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { - render, fireEvent, screen, waitFor, -} from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import FormCheckbox from '../FormCheckbox'; import FormGroup from '../FormGroup'; @@ -46,11 +45,11 @@ describe('FormCheckbox', () => { expect(describerNode).toBeInTheDocument(); }); - it('calls the change handler', () => { + it('calls the change handler', async () => { render(FormCheckboxComponent()); const inputNode = screen.getByLabelText('Green'); - fireEvent.change(inputNode, { target: { value: 'green' } }); + await userEvent.type(inputNode, 'green'); waitFor(() => { expect(handleChange).toHaveBeenCalledWith( @@ -62,11 +61,11 @@ describe('FormCheckbox', () => { }); }); - it('calls the focus handler', () => { + it('calls the focus handler', async () => { render(FormCheckboxComponent()); const inputNode = screen.getByLabelText('Green'); - fireEvent.focus(inputNode); + inputNode.focus(); expect(handleFocus).toHaveBeenCalledWith( expect.objectContaining({ @@ -76,11 +75,12 @@ describe('FormCheckbox', () => { ); }); - it('calls the blur handler', () => { + it('calls the blur handler', async () => { render(FormCheckboxComponent()); const inputNode = screen.getByLabelText('Green'); - fireEvent.blur(inputNode); + inputNode.focus(); + await userEvent.tab(); expect(handleBlur).toHaveBeenCalledWith( expect.objectContaining({ @@ -92,10 +92,6 @@ describe('FormCheckbox', () => { }); describe('FormCheckbox with FormGroup', () => { - // const handleChange = jest.fn(); - // const handleFocus = jest.fn(); - // const handleBlur = jest.fn(); - it('renders a group with a label', () => { render( diff --git a/src/Form/tests/FormCheckboxSet.test.jsx b/src/Form/tests/FormCheckboxSet.test.jsx index ea0ea65330..be5c0a9082 100644 --- a/src/Form/tests/FormCheckboxSet.test.jsx +++ b/src/Form/tests/FormCheckboxSet.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import FormGroup from '../FormGroup'; @@ -101,7 +101,7 @@ describe('FormCheckboxSet', () => { it('calls the change handlers with the right value', async () => { renderFormWithoutLabel(); const checkboxNode = screen.getByLabelText('green'); - await userEvent.type(checkboxNode, { target: { value: 'green' } }); + await userEvent.type(checkboxNode, 'green'); expect(setValue).toHaveBeenCalledWith('green'); }); }); @@ -110,7 +110,7 @@ describe('FormCheckboxSet', () => { it('calls the change handlers with the right value', async () => { renderFormWithHandlers(); const checkboxNode = screen.getByLabelText('green'); - await userEvent.type(checkboxNode, { target: { value: 'green' } }); + await userEvent.type(checkboxNode, 'green'); expect(onChange).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ value: 'green' }), @@ -119,10 +119,11 @@ describe('FormCheckboxSet', () => { ); }); - it('calls the focus handler', () => { + it('calls the focus handler', async () => { renderFormWithHandlers(); const checkboxNode = screen.getByLabelText('green'); - fireEvent.focus(checkboxNode); + checkboxNode.focus(); + await userEvent.tab(); expect(onFocus).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ value: 'green' }), @@ -131,10 +132,11 @@ describe('FormCheckboxSet', () => { ); }); - it('calls the blur handler', () => { + it('calls the blur handler', async () => { renderFormWithHandlers(); const checkboxNode = screen.getByLabelText('green'); - fireEvent.blur(checkboxNode); + checkboxNode.focus(); + await userEvent.tab(); expect(onBlur).toHaveBeenCalledWith( expect.objectContaining({ target: expect.objectContaining({ value: 'green' }), diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index 59e0c93d48..95044c3f75 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import FormControl from '../FormControl'; @@ -8,9 +9,10 @@ const ref = { }; describe('FormControl', () => { - it('textarea changes its height with autoResize prop', () => { + it('textarea changes its height with autoResize prop', async () => { const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref); const onChangeFunc = jest.fn(); + const inputText = 'new text'; render( , ); @@ -24,9 +26,9 @@ describe('FormControl', () => { expect(useReferenceSpy).toHaveBeenCalledTimes(1); expect(ref.current.style.height).toBe('0px'); - fireEvent.change(textarea, { target: { value: 'new text' } }); + await userEvent.type(textarea, inputText); - expect(onChangeFunc).toHaveBeenCalledTimes(1); + expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length); expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`); }); }); diff --git a/src/Form/tests/FormRadioSet.test.jsx b/src/Form/tests/FormRadioSet.test.jsx index d579e09063..4d5a5d0a66 100644 --- a/src/Form/tests/FormRadioSet.test.jsx +++ b/src/Form/tests/FormRadioSet.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import FormGroup from '../FormGroup'; import FormRadioSet from '../FormRadioSet'; @@ -75,10 +76,10 @@ describe('FormRadioSet', () => { expect(redRadio).toBeChecked(); }); - it('calls the change handlers with the right value', () => { + it('calls the change handlers with the right value', async () => { renderFormRadioSet(); const greenRadio = screen.getByLabelText('green'); - fireEvent.click(greenRadio); + await userEvent.click(greenRadio); expect(setValue).toHaveBeenCalledWith('green'); }); }); diff --git a/src/Form/tests/fieldUtils.test.jsx b/src/Form/tests/fieldUtils.test.jsx index 18a56d80bb..688db28ab2 100644 --- a/src/Form/tests/fieldUtils.test.jsx +++ b/src/Form/tests/fieldUtils.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { - render, fireEvent, waitFor, screen, -} from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { callAllHandlers, @@ -82,18 +81,18 @@ describe('useIdList', () => { expect(renderedIds[1]).toBe('prefix-2'); }); it('registers an explicit id', () => { - const { getByTestId } = render( + render( , ); - const idList = getByTestId('id-list'); + const idList = screen.getByTestId('id-list'); const renderedIds = idList.textContent.split(' '); expect(renderedIds[2]).toBe('explicit-id'); }); }); describe('with no default', () => { it('only has the two ids', () => { - const { getByTestId } = render(); - const idList = getByTestId('id-list'); + render(); + const idList = screen.getByTestId('id-list'); const renderedIds = idList.textContent.split(' '); expect(renderedIds.length).toBe(2); }); @@ -131,10 +130,10 @@ describe('useHasValue', () => { it('has value when a target blur event has a value', async () => { render(); const input = screen.getByTestId('input'); - fireEvent.blur(input, { target: { value: 'hello' } }); - await waitFor(() => { - expect(screen.getByTestId('has-value')).toBeInTheDocument(); - }); + await userEvent.type(input, 'hello'); + await userEvent.tab(); + + expect(screen.getByTestId('has-value')).toBeInTheDocument(); }); }); }); @@ -151,10 +150,10 @@ describe('uncontrolled input with a default value', () => { , ); const input = screen.getByTestId('input'); - fireEvent.blur(input, { target: { value: '' } }); - await waitFor(() => { - expect(screen.queryByTestId('has-value')).toBe(null); - }); + await userEvent.type(input, ''); + await userEvent.tab(); + + expect(screen.queryByTestId('has-value')).toBe(null); }); }); @@ -168,10 +167,10 @@ describe('controlled value', () => { async () => { render(); const input = screen.getByTestId('input'); - fireEvent.blur(input, { target: { value: '' } }); - await waitFor(() => { - expect(screen.getByTestId('has-value')).toBeInTheDocument(); - }); + await userEvent.type(input, ''); + await userEvent.tab(); + + expect(screen.getByTestId('has-value')).toBeInTheDocument(); }, ); }); diff --git a/src/Form/tests/useCheckboxSetValues.test.jsx b/src/Form/tests/useCheckboxSetValues.test.jsx index f146f2558f..ecb38cb98a 100644 --- a/src/Form/tests/useCheckboxSetValues.test.jsx +++ b/src/Form/tests/useCheckboxSetValues.test.jsx @@ -1,6 +1,8 @@ /* eslint-disable react/button-has-type */ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + import useCheckboxSetValues from '../useCheckboxSetValues'; const VALUES = 'values'; @@ -27,42 +29,42 @@ describe('useCheckboxSetValues', () => { expect(values.textContent).toBe('cheddar'); }); - it('can append a value', () => { + it('can append a value', async () => { render(); const addButton = screen.getByTestId('add'); const values = screen.getByTestId(VALUES); - fireEvent.click(addButton); + await userEvent.click(addButton); expect(values.textContent).toBe('cheddar provolone'); }); - it('can remove a value', () => { + it('can remove a value', async () => { render(); const removeButton = screen.getByTestId('remove'); const values = screen.getByTestId(VALUES); - fireEvent.click(removeButton); + await userEvent.click(removeButton); expect(values.textContent).toBe('cheddar'); }); - it('can replace all values', () => { + it('can replace all values', async () => { render(); const setButton = screen.getByTestId('set'); const values = screen.getByTestId(VALUES); - fireEvent.click(setButton); + await userEvent.click(setButton); expect(values.textContent).toBe('cheddar swiss provolone'); }); - it('can clear all values', () => { + it('can clear all values', async () => { render(); const clearButton = screen.getByTestId('clear'); const values = screen.getByTestId(VALUES); - fireEvent.click(clearButton); + await userEvent.click(clearButton); expect(values.textContent).toBe(''); }); diff --git a/src/Hyperlink/Hyperlink.test.jsx b/src/Hyperlink/Hyperlink.test.jsx index f1d2715682..2d5ffd3c5e 100644 --- a/src/Hyperlink/Hyperlink.test.jsx +++ b/src/Hyperlink/Hyperlink.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import Hyperlink from '.'; @@ -21,7 +22,7 @@ const externalLinkProps = { }; describe('correct rendering', () => { - it('renders Hyperlink', () => { + it('renders Hyperlink', async () => { const { getByRole } = render(); const wrapper = getByRole('link'); expect(wrapper).toBeInTheDocument(); @@ -31,7 +32,7 @@ describe('correct rendering', () => { expect(wrapper).toHaveAttribute('href', destination); expect(wrapper).toHaveAttribute('target', '_self'); - fireEvent.click(wrapper); + await userEvent.click(wrapper); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -62,11 +63,11 @@ describe('event handlers are triggered correctly', () => { let spy; beforeEach(() => { spy = jest.fn(); }); - it('should fire onClick', () => { + it('should fire onClick', async () => { const { getByRole } = render(); const wrapper = getByRole('link'); expect(spy).toHaveBeenCalledTimes(0); - fireEvent.click(wrapper); + await userEvent.click(wrapper); expect(spy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/IconButton/IconButton.test.jsx b/src/IconButton/IconButton.test.jsx index 3e703d0d4e..9f098002ea 100644 --- a/src/IconButton/IconButton.test.jsx +++ b/src/IconButton/IconButton.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; import renderer from 'react-test-renderer'; +import userEvent from '@testing-library/user-event'; import { InfoOutline } from '../../icons'; import IconButton from '.'; @@ -64,15 +65,15 @@ describe('', () => { }); describe('onClick', () => { - it('performs the onClick action when clicked', () => { + it('performs the onClick action when clicked', async () => { const spy = jest.fn(); const { getByRole } = render(); const button = getByRole('button'); - fireEvent.click(button); + await userEvent.click(button); expect(spy).toHaveBeenCalledTimes(1); }); - it('only clicks one icon at a time', () => { + it('only clicks one icon at a time', async () => { const spy1 = jest.fn(); const spy2 = jest.fn(); const { getAllByRole } = render( @@ -84,11 +85,11 @@ describe('', () => { const buttons = getAllByRole('button'); - fireEvent.click(buttons[0]); + await userEvent.click(buttons[0]); expect(spy1).toHaveBeenCalledTimes(1); expect(spy2).toHaveBeenCalledTimes(0); - fireEvent.click(buttons[1]); + await userEvent.click(buttons[1]); expect(spy1).toHaveBeenCalledTimes(1); expect(spy2).toHaveBeenCalledTimes(1); }); diff --git a/src/ListBox/ListBox.test.jsx b/src/ListBox/ListBox.test.jsx index 2be21c5207..19da147012 100644 --- a/src/ListBox/ListBox.test.jsx +++ b/src/ListBox/ListBox.test.jsx @@ -1,65 +1,54 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import ListBox from '.'; import ListBoxOption from '../ListBoxOption'; describe('ListBox', () => { - let getByTestId; - let getAllByRole; - beforeEach(() => { - const renderResult = render( - + render( + test1 test2 test3 , ); - getByTestId = renderResult.getByTestId; - getAllByRole = renderResult.getAllByRole; }); it('should have null aria-activedescendant attribute by default', () => { - const listBoxElement = getByTestId('listbox'); + const listBoxElement = screen.getByRole('listbox'); expect(listBoxElement.getAttribute('aria-activedescendant')).toBeNull(); }); - it('should have correct aria-activedescendant attribute when selectedOptionIndex state is non-null', () => { - const listBoxElement = getByTestId('listbox'); - const selectedOptionIndex = 1; + it( + 'should have correct aria-activedescendant attribute when selectedOptionIndex state is non-null', + async () => { + const listBoxElement = screen.getByRole('listbox'); + const selectedOptionIndex = 1; - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); - expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual(`list-box-option-${selectedOptionIndex}`); - }); + expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual(`list-box-option-${selectedOptionIndex}`); + }, + ); - it('selectedOptionIndex prop should override selectedOptionIndex state', () => { - const listBoxElement = getByTestId('listbox'); + it('selectedOptionIndex prop should override selectedOptionIndex state', async () => { + const listBoxElement = screen.getByRole('listbox'); const selectedOptionIndex = 2; - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); - - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual(`list-box-option-${selectedOptionIndex}`); }); it('should render a div by default', () => { - const listBoxElement = getByTestId('listbox'); + const listBoxElement = screen.getByRole('listbox'); expect(listBoxElement.tagName.toLowerCase()).toBe('div'); }); @@ -74,130 +63,99 @@ describe('ListBox', () => { }); it('should have correct default classNames', () => { - const listBoxElement = getByTestId('listbox'); + const listBoxElement = screen.getByRole('listbox'); expect(listBoxElement).toHaveClass('list-group'); }); it('should have listbox role', () => { - const listBoxElement = getByTestId('listbox'); + const listBoxElement = screen.getByRole('listbox'); expect(listBoxElement).toHaveAttribute('role', 'listbox'); }); it('should have 0 tabIndex', () => { - const listBoxElement = getByTestId('listbox'); + const listBoxElement = screen.getByRole('listbox'); expect(listBoxElement).toHaveAttribute('tabIndex', '0'); }); - it('should select first ListBoxOption on focus if not ListBoxOption selected', () => { - const listBoxElement = getByTestId('listbox'); + it('should select first ListBoxOption on focus if not ListBoxOption selected', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); }); - it('should not select first ListBoxOption on focus if ListBoxOption selected', () => { - const listBoxElement = getByTestId('listbox'); + it('should not select first ListBoxOption on focus if ListBoxOption selected', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-1'); }); - it('should select next ListBoxOption on down arrow key', () => { - const listBoxElement = getByTestId('listbox'); + it('should select next ListBoxOption on down arrow key', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-1'); }); - it('should not select next ListBoxOption on down arrow key if at end of list', () => { - const listBoxElement = getByTestId('listbox'); - - fireEvent.focus(listBoxElement); + it('should not select next ListBoxOption on down arrow key if at end of list', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); - - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowdown}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-2'); }); - it('should select previous ListBoxOption on up arrow key', () => { - const listBoxElement = getByTestId('listbox'); - - fireEvent.focus(listBoxElement); + it('should select previous ListBoxOption on up arrow key', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowDown', - preventDefault: () => {}, - }); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowUp', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowdown}'); + await userEvent.keyboard('{arrowup}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); }); - it('should not select previous ListBoxOption on up arrow key if at start of list', () => { - const listBoxElement = getByTestId('listbox'); + it('should not select previous ListBoxOption on up arrow key if at start of list', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'ArrowUp', - preventDefault: () => {}, - }); + await userEvent.keyboard('{arrowup}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); }); - it('should not change ListBoxOption selection on non-supported key', () => { - const listBoxElement = getByTestId('listbox'); + it('should not change ListBoxOption selection on non-supported key', async () => { + const listBoxElement = screen.getByRole('listbox'); - fireEvent.focus(listBoxElement); + listBoxElement.focus(); - fireEvent.keyDown(listBoxElement, { - key: 'leftArrow', - preventDefault: () => {}, - }); + await userEvent.keyboard('{leftarrow}'); expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); }); - it('should update state when child\'s onSelect is called', () => { - const listBoxElement = getByTestId('listbox'); - const listBoxOption2 = getAllByRole('option')[1]; + it('should update state when child\'s onSelect is called', async () => { + const listBoxElement = screen.getByRole('listbox'); + const listBoxOption2 = screen.getAllByRole('option')[1]; - fireEvent.focus(listBoxElement.firstChild); - fireEvent.click(listBoxOption2); + await userEvent.click(listBoxOption2); - expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-0'); + expect(listBoxElement.getAttribute('aria-activedescendant')).toEqual('list-box-option-1'); }); }); diff --git a/src/ListBoxOption/ListBoxOption.test.jsx b/src/ListBoxOption/ListBoxOption.test.jsx index 3e48a4e29a..c192aa4305 100644 --- a/src/ListBoxOption/ListBoxOption.test.jsx +++ b/src/ListBoxOption/ListBoxOption.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import ListBoxOption from '.'; @@ -8,20 +9,20 @@ describe('ListBoxOption', () => { describe('rendering', () => { it('should have false aria-selected attribute by default', () => { - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement.getAttribute('aria-selected')).toEqual('false'); }); it('should have false aria-selected attribute when isSelected prop is false', () => { - const { getByTestId, rerender } = render( + const { rerender } = render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement.getAttribute('aria-selected')).toEqual('false'); rerender( @@ -50,39 +51,39 @@ describe('ListBoxOption', () => { }); it('should have correct default classNames', () => { - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement).toHaveClass('list-group-item'); expect(listBoxOptionElement).toHaveClass('list-group-item-action'); }); it('should not have active className by default', () => { - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement).not.toHaveClass('active'); }); it('should have correct default id', () => { - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement.getAttribute('id')).toBeNull(); }); it('should have correct id when index prop is a number', () => { - const { getByTestId, rerender } = render( + const { rerender } = render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement.getAttribute('id')).toEqual('list-box-option-1'); rerender( @@ -93,20 +94,20 @@ describe('ListBoxOption', () => { }); it('should have option role', () => { - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement.getAttribute('role')).toEqual('option'); }); it('should have active className when isSelected prop is true', () => { - const { getByTestId, rerender } = render( + const { rerender } = render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); expect(listBoxOptionElement).not.toHaveClass('active'); rerender( @@ -118,28 +119,28 @@ describe('ListBoxOption', () => { }); describe('behavior', () => { - it('should call onSelect on mouse down', () => { + it('should call onSelect on mouse down', async () => { const onSelectSpy = jest.fn(); - const { getByTestId } = render( + render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); - fireEvent.mouseDown(listBoxOptionElement); + await userEvent.click(listBoxOptionElement); expect(onSelectSpy).toHaveBeenCalledTimes(1); }); - it('should call onSelect when receiving new isSelected prop', () => { + it('should call onSelect when receiving new isSelected prop', async () => { const onSelectSpy = jest.fn(); - const { getByTestId, rerender } = render( + const { rerender } = render( {listBoxOptionChild}, ); - const listBoxOptionElement = getByTestId('listbox-option'); + const listBoxOptionElement = screen.getByTestId('listbox-option'); - fireEvent.mouseDown(listBoxOptionElement); + await userEvent.click(listBoxOptionElement); rerender( diff --git a/src/Menu/Menu.test.jsx b/src/Menu/Menu.test.jsx index 211fefb6b3..1bc882113f 100644 --- a/src/Menu/Menu.test.jsx +++ b/src/Menu/Menu.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import renderer from 'react-test-renderer'; import userEvent from '@testing-library/user-event'; @@ -33,7 +33,7 @@ describe('Menu Item renders correctly', () => { expect(tree).toMatchSnapshot(); }); - it('Renders disabled menu items, but you can\'t click them', () => { + it('Renders disabled menu items, but you can\'t click them', async () => { const clickFn = jest.fn(); render( @@ -49,7 +49,7 @@ describe('Menu Item renders correctly', () => { ); const button = screen.getByText(MENU_ITEM_TEXT); - fireEvent.click(button); + await userEvent.click(button); expect(clickFn).toHaveBeenCalledTimes(0); }); }); @@ -65,10 +65,9 @@ describe('Keyboard Interactions', () => { ); }); - it('should focus on the first item after click', () => { + it('should focus on the first item after click', async () => { const defaultItem = screen.getByText('Default').parentElement; - fireEvent.click(defaultItem); - userEvent.tab(); + await userEvent.click(defaultItem); expect(defaultItem).toHaveFocus(); }); diff --git a/src/Menu/MenuItem.test.jsx b/src/Menu/MenuItem.test.jsx index a980983a02..dc59443549 100644 --- a/src/Menu/MenuItem.test.jsx +++ b/src/Menu/MenuItem.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import renderer from 'react-test-renderer'; +import userEvent from '@testing-library/user-event'; import { Add, Check } from '../../icons'; import { MenuItem } from '..'; @@ -16,7 +17,7 @@ describe('Menu Item', () => { expect(tree).toMatchSnapshot(); }); - it('The Button can be clicked', () => { + it('The Button can be clicked', async () => { const clickFn = jest.fn(); render( @@ -25,12 +26,12 @@ describe('Menu Item', () => { ); const button = screen.getByRole('button'); - fireEvent.click(button); + await userEvent.click(button); expect(clickFn).toHaveBeenCalledTimes(1); }); - it('Disabled Button can\'t be clicked', () => { + it('Disabled Button can\'t be clicked', async () => { const clickFn = jest.fn(); render( @@ -39,7 +40,7 @@ describe('Menu Item', () => { ); const button = screen.getByRole('button'); - fireEvent.click(button); + await userEvent.click(button); expect(clickFn).toHaveBeenCalledTimes(0); }); diff --git a/src/Menu/SelectMenu.test.jsx b/src/Menu/SelectMenu.test.jsx index 25c943a7ae..9d542da4e2 100644 --- a/src/Menu/SelectMenu.test.jsx +++ b/src/Menu/SelectMenu.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import renderer from 'react-test-renderer'; import userEvent from '@testing-library/user-event'; @@ -82,7 +82,7 @@ describe('mouse behavior & keyboard behavior', () => { const menuTrigger = getByRole('button', { expanded: false }); await userEvent.click(menuTrigger); const menuItems = getAllByRole('link'); - fireEvent.click(menuItems[7]); + await userEvent.click(menuItems[7]); expect(menuTrigger).toHaveFocus(); }); }); diff --git a/src/Modal/ModalCloseButton.test.jsx b/src/Modal/ModalCloseButton.test.jsx deleted file mode 100644 index d4877fcd22..0000000000 --- a/src/Modal/ModalCloseButton.test.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; -import { ModalContextProvider } from './ModalContext'; -import ModalCloseButton from './ModalCloseButton'; - -describe('', () => { - it('calls a modal context close function on click', () => { - const mockClose = jest.fn(); - render( - - Close - , - ); - - const closeButton = screen.getByText('Close'); - fireEvent.click(closeButton); - - expect(mockClose).toHaveBeenCalled(); - }); - - it('calls both the modal context close function and a passed click handler', () => { - const mockClose = jest.fn(); - const mockOnClick = jest.fn(); - render( - - Close - , - ); - - const closeButton = screen.getByText('Close'); - fireEvent.click(closeButton); - - expect(mockClose).toHaveBeenCalled(); - expect(mockOnClick).toHaveBeenCalled(); - }); -}); diff --git a/src/Modal/AlertModal.test.jsx b/src/Modal/tests/AlertModal.test.jsx similarity index 94% rename from src/Modal/AlertModal.test.jsx rename to src/Modal/tests/AlertModal.test.jsx index 0db0f768f2..634d579346 100644 --- a/src/Modal/AlertModal.test.jsx +++ b/src/Modal/tests/AlertModal.test.jsx @@ -1,11 +1,11 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import AlertModal from './AlertModal'; -import { Info } from '../../icons'; +import AlertModal from '../AlertModal'; +import { Info } from '../../../icons'; /* eslint-disable react/prop-types */ -jest.mock('./Portal', () => function PortalMock(props) { +jest.mock('../Portal', () => function PortalMock(props) { const { children, ...otherProps } = props; return ( diff --git a/src/Modal/Modal.test.jsx b/src/Modal/tests/Modal.test.jsx similarity index 92% rename from src/Modal/Modal.test.jsx rename to src/Modal/tests/Modal.test.jsx index 33b3adb0a0..76359ea674 100644 --- a/src/Modal/Modal.test.jsx +++ b/src/Modal/tests/Modal.test.jsx @@ -1,9 +1,10 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; -import Modal from '.'; -import { Button } from '..'; -import Variant from '../utils/constants'; +import Modal from '..'; +import { Button } from '../..'; +import Variant from '../../utils/constants'; const modalOpen = (isOpen, container) => { if (!isOpen) { @@ -175,38 +176,38 @@ describe('', () => { }); describe('close functions properly', () => { - it('closes when x button pressed', () => { + it('closes when x button pressed', async () => { render(); modalOpen(true, screen); - fireEvent.click(screen.queryAllByRole('button')[0]); + await userEvent.click(screen.queryAllByRole('button')[0]); modalOpen(false, screen); }); - it('closes when Close button pressed', () => { + it('closes when Close button pressed', async () => { render(); modalOpen(true, screen); - fireEvent.click(screen.queryAllByRole('button')[1]); + await userEvent.click(screen.queryAllByRole('button')[1]); modalOpen(false, screen); }); - it('calls callback function on close', () => { + it('calls callback function on close', async () => { const spy = jest.fn(); render(); expect(spy).toHaveBeenCalledTimes(0); // press X button - fireEvent.click(screen.queryAllByRole('button')[0]); + await userEvent.click(screen.queryAllByRole('button')[0]); expect(spy).toHaveBeenCalledTimes(1); }); - it('reopens after closed', () => { + it('reopens after closed', async () => { const { rerender } = render(); modalOpen(true, screen); - fireEvent.click(screen.queryAllByRole('button')[0]); + await userEvent.click(screen.queryAllByRole('button')[0]); modalOpen(false, screen); rerender(); modalOpen(true, screen); diff --git a/src/Modal/tests/ModalCloseButton.test.jsx b/src/Modal/tests/ModalCloseButton.test.jsx new file mode 100644 index 0000000000..e5eb8dc58f --- /dev/null +++ b/src/Modal/tests/ModalCloseButton.test.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { ModalContextProvider } from '../ModalContext'; +import ModalCloseButton from '../ModalCloseButton'; + +describe('', () => { + it('calls a modal context close function on click', async () => { + const mockClose = jest.fn(); + render( + + Close + , + ); + + const closeButton = screen.getByText('Close'); + await userEvent.click(closeButton); + + expect(mockClose).toHaveBeenCalled(); + }); + + it( + 'calls both the modal context close function and a passed click handler', + async () => { + const mockClose = jest.fn(); + const mockOnClick = jest.fn(); + render( + + Close + , + ); + + const closeButton = screen.getByText('Close'); + await userEvent.click(closeButton); + + expect(mockClose).toHaveBeenCalled(); + expect(mockOnClick).toHaveBeenCalled(); + }, + ); +}); diff --git a/src/Modal/ModalLayer.test.jsx b/src/Modal/tests/ModalLayer.test.jsx similarity index 84% rename from src/Modal/ModalLayer.test.jsx rename to src/Modal/tests/ModalLayer.test.jsx index 930c7f2787..22cc96f59d 100644 --- a/src/Modal/ModalLayer.test.jsx +++ b/src/Modal/tests/ModalLayer.test.jsx @@ -1,9 +1,11 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; -import ModalLayer from './ModalLayer'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import ModalLayer from '../ModalLayer'; /* eslint-disable react/prop-types */ -jest.mock('./Portal', () => function PortalMock(props) { +jest.mock('../Portal', () => function PortalMock(props) { const { children, ...otherProps } = props; return ( @@ -71,7 +73,7 @@ describe('', () => { }); describe('Backdrop', () => { - it('closes a non-blocking modal layer when clicked', () => { + it('closes a non-blocking modal layer when clicked', async () => { const closeFn = jest.fn(); render( @@ -80,11 +82,11 @@ describe('', () => { ); const backdrop = screen.getByTestId('modal-backdrop'); - fireEvent.click(backdrop); + await userEvent.click(backdrop); expect(closeFn).toHaveBeenCalled(); }); - it('does not close a blocking modal layer when clicked', () => { + it('does not close a blocking modal layer when clicked', async () => { const closeFn = jest.fn(); render( @@ -93,7 +95,7 @@ describe('', () => { ); const backdrop = screen.getByTestId('modal-backdrop'); - fireEvent.click(backdrop); + await userEvent.click(backdrop); expect(closeFn).not.toHaveBeenCalled(); }); }); diff --git a/src/Modal/ModalPopup.test.jsx b/src/Modal/tests/ModalPopup.test.jsx similarity index 97% rename from src/Modal/ModalPopup.test.jsx rename to src/Modal/tests/ModalPopup.test.jsx index d282b7dfc2..faae44e701 100644 --- a/src/Modal/ModalPopup.test.jsx +++ b/src/Modal/tests/ModalPopup.test.jsx @@ -1,9 +1,9 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import ModalPopup from './ModalPopup'; +import ModalPopup from '../ModalPopup'; /* eslint-disable react/prop-types */ -jest.mock('./Portal', () => function PortalMock(props) { +jest.mock('../Portal', () => function PortalMock(props) { const { children, ...otherProps } = props; return ( diff --git a/src/Modal/PopperElement.test.jsx b/src/Modal/tests/PopperElement.test.jsx similarity index 96% rename from src/Modal/PopperElement.test.jsx rename to src/Modal/tests/PopperElement.test.jsx index 195c479a44..00c2e19142 100644 --- a/src/Modal/PopperElement.test.jsx +++ b/src/Modal/tests/PopperElement.test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { usePopper } from 'react-popper'; -import PopperElement from './PopperElement'; +import PopperElement from '../PopperElement'; jest.mock('react-popper', () => ({ usePopper: jest.fn(() => ({ diff --git a/src/Modal/Portal.test.jsx b/src/Modal/tests/Portal.test.jsx similarity index 97% rename from src/Modal/Portal.test.jsx rename to src/Modal/tests/Portal.test.jsx index 231ea701a8..0f3ec32d70 100644 --- a/src/Modal/Portal.test.jsx +++ b/src/Modal/tests/Portal.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { render } from '@testing-library/react'; -import Portal from './Portal'; +import Portal from '../Portal'; const getPortalRoot = () => global.document.getElementById('paragon-portal-root'); diff --git a/src/PageBanner/PageBanner.test.jsx b/src/PageBanner/PageBanner.test.jsx index 6a647ee720..34cbcac596 100644 --- a/src/PageBanner/PageBanner.test.jsx +++ b/src/PageBanner/PageBanner.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import PageBanner from '.'; @@ -47,7 +48,7 @@ describe('', () => { const spy = jest.fn(); render(); const dismissButton = screen.getByRole('button'); - await fireEvent.click(dismissButton); + await userEvent.click(dismissButton); expect(spy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/Pagination/Pagination.test.jsx b/src/Pagination/Pagination.test.jsx index 33a692a562..98f13d30ab 100644 --- a/src/Pagination/Pagination.test.jsx +++ b/src/Pagination/Pagination.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; -import { - render, fireEvent, act, screen, -} from '@testing-library/react'; +import { render, act, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + import { Context as ResponsiveContext } from 'react-responsive'; import breakpoints from '../utils/breakpoints'; @@ -68,7 +68,7 @@ describe('', () => { }); describe('handles focus properly', () => { - it('should change focus to next button if previous page is first page', () => { + it('should change focus to next button if previous page is first page', async () => { const props = { ...baseProps, currentPage: 2, @@ -76,11 +76,11 @@ describe('', () => { render(); const previousButton = screen.getByLabelText(/Previous/); const nextButton = screen.getByLabelText(/Next/); - fireEvent.click(previousButton); + await userEvent.click(previousButton); expect(document.activeElement).toEqual(nextButton); }); - it('should change focus to previous button if next page is last page', () => { + it('should change focus to previous button if next page is last page', async () => { const props = { ...baseProps, currentPage: baseProps.pageCount - 1, @@ -88,7 +88,7 @@ describe('', () => { render(); const previousButton = screen.getByLabelText(/Previous/); const nextButton = screen.getByLabelText(/Next/); - fireEvent.click(nextButton); + await userEvent.click(nextButton); expect(document.activeElement).toEqual(previousButton); }); }); @@ -129,7 +129,7 @@ describe('', () => { }); describe('should fire callbacks properly', () => { - it('should not fire onPageSelect when selecting current page', () => { + it('should not fire onPageSelect when selecting current page', async () => { const spy = jest.fn(); const props = { ...baseProps, @@ -142,11 +142,11 @@ describe('', () => { ); const previousButton = screen.getByLabelText(/Previous/); - fireEvent.click(previousButton); + await userEvent.click(previousButton); expect(spy).toHaveBeenCalledTimes(0); }); - it('should fire onPageSelect callback when selecting new page', () => { + it('should fire onPageSelect callback when selecting new page', async () => { const spy = jest.fn(); const props = { ...baseProps, @@ -159,17 +159,17 @@ describe('', () => { ); const pageButtons = screen.getAllByLabelText(/^Page/); - fireEvent.click(pageButtons[1]); + await userEvent.click(pageButtons[1]); expect(spy).toHaveBeenCalledTimes(1); - fireEvent.click(pageButtons[2]); + await userEvent.click(pageButtons[2]); expect(spy).toHaveBeenCalledTimes(2); }); }); }); describe('fires previous and next button click handlers', () => { - it('previous button onClick', () => { + it('previous button onClick', async () => { const spy = jest.fn(); const props = { ...baseProps, @@ -177,18 +177,18 @@ describe('', () => { onPageSelect: spy, }; render(); - fireEvent.click(screen.getByLabelText(/Previous/)); + await userEvent.click(screen.getByLabelText(/Previous/)); expect(spy).toHaveBeenCalledTimes(1); }); - it('next button onClick', () => { + it('next button onClick', async () => { const spy = jest.fn(); const props = { ...baseProps, onPageSelect: spy, }; render(); - fireEvent.click(screen.getByLabelText(/Next/)); + await userEvent.click(screen.getByLabelText(/Next/)); expect(spy).toHaveBeenCalledTimes(1); }); }); @@ -220,13 +220,13 @@ describe('', () => { ); } - it('uses passed in previous button label', () => { + it('uses passed in previous button label', async () => { render( , ); expect(screen.getByText(buttonLabels.previous)).toBeInTheDocument(); - fireEvent.click(screen.getByText(buttonLabels.next)); + await userEvent.click(screen.getByText(buttonLabels.next)); expect(screen.getByLabelText(`${buttonLabels.previous}, ${buttonLabels.page} 4`)).toBeInTheDocument(); }); @@ -271,7 +271,7 @@ describe('', () => { const dropdownButton = screen.getByRole('button', { name: /1 of 5/i, attributes: { 'aria-haspopup': 'true' } }); expect(dropdownButton.textContent).toContain(`${baseProps.state.pageIndex} of ${baseProps.pageCount}`); - fireEvent.click(dropdownButton); + await userEvent.click(dropdownButton); await act(async () => { const dropdownChoices = screen.getAllByTestId('pagination-dropdown-item'); diff --git a/src/ProductTour/Checkpoint.test.jsx b/src/ProductTour/Checkpoint.test.jsx index 5fab84600f..abb440ca68 100644 --- a/src/ProductTour/Checkpoint.test.jsx +++ b/src/ProductTour/Checkpoint.test.jsx @@ -1,5 +1,7 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + import * as popper from '@popperjs/core'; import Checkpoint from './Checkpoint'; @@ -57,15 +59,15 @@ describe('Checkpoint', () => { expect(screen.getByRole('button', { name: 'Next' })).toBeInTheDocument(); }); - it('dismiss button onClick calls handleDismiss', () => { + it('dismiss button onClick calls handleDismiss', async () => { const dismissButton = screen.getByRole('button', { name: 'Dismiss' }); - fireEvent.click(dismissButton); + await userEvent.click(dismissButton); expect(handleDismiss).toHaveBeenCalledTimes(1); }); - it('advance button onClick calls handleAdvance', () => { + it('advance button onClick calls handleAdvance', async () => { const advanceButton = screen.getByRole('button', { name: 'Next' }); - fireEvent.click(advanceButton); + await userEvent.click(advanceButton); expect(handleAdvance).toHaveBeenCalledTimes(1); }); }); @@ -96,9 +98,9 @@ describe('Checkpoint', () => { expect(screen.getByText('End', { selector: 'button' })).toBeInTheDocument(); }); - it('end button onClick calls handleEnd', () => { + it('end button onClick calls handleEnd', async () => { const endButton = screen.getByText('End', { selector: 'button' }); - fireEvent.click(endButton); + await userEvent.click(endButton, undefined, { skipPointerEventsCheck: true }); expect(handleEnd).toHaveBeenCalledTimes(1); }); }); diff --git a/src/ProductTour/ProductTour.test.jsx b/src/ProductTour/ProductTour.test.jsx index 580f8512be..4be189efb5 100644 --- a/src/ProductTour/ProductTour.test.jsx +++ b/src/ProductTour/ProductTour.test.jsx @@ -1,5 +1,7 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + import * as popper from '@popperjs/core'; import ProductTour from '.'; @@ -100,8 +102,8 @@ describe('', () => { expect(screen.getByTestId('pgn__checkpoint-breadcrumb_active')).toBeInTheDocument(); }); - it('onClick of advance button advances to next checkpoint', () => { - render( + it('onClick of advance button advances to next checkpoint', async () => { + const { rerender } = render( <> ', () => { {targets} , ); - // Verify the first Checkpoint has rendered expect(screen.getByRole('heading', { name: 'Checkpoint 1' })).toBeInTheDocument(); // Click the advance button const advanceButton = screen.getByRole('button', { name: 'Next' }); - fireEvent.click(advanceButton); + await userEvent.click(advanceButton); + + rerender( + <> + + {targets} + , + ); + + const heading = screen.getByRole('heading', { name: 'Checkpoint 2' }); // Verify the second Checkpoint has rendered - expect(screen.getByRole('heading', { name: 'Checkpoint 2' })).toBeInTheDocument(); + expect(heading).toBeInTheDocument(); }); - it('onClick of dismiss button disables tour', () => { + it('onClick of dismiss button disables tour', async () => { render( <> ', () => { // Click the dismiss button const dismissButton = screen.getByRole('button', { name: 'Dismiss' }); expect(dismissButton).toBeInTheDocument(); - fireEvent.click(dismissButton); + await userEvent.click(dismissButton); // Verify no Checkpoints have rendered expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); }); - it('onClick of end button disables tour', () => { - render( + it('onClick of end button disables tour', async () => { + const { rerender } = render( <> ', () => { // Advance the Tour to the last Checkpoint const advanceButton1 = screen.getByRole('button', { name: 'Next' }); - fireEvent.click(advanceButton1); + await userEvent.click(advanceButton1); const advanceButton2 = screen.getByRole('button', { name: 'Next' }); - fireEvent.click(advanceButton2); + await userEvent.click(advanceButton2); + + rerender( + <> + + {targets} + , + ); + const advanceButton3 = screen.getByRole('button', { name: 'Override advance' }); - fireEvent.click(advanceButton3); + await userEvent.click(advanceButton3); + + rerender( + <> + + {targets} + , + ); // Click the end button const endButton = screen.getByRole('button', { name: 'End' }); - fireEvent.click(endButton); + await userEvent.click(endButton); // Verify no Checkpoints have rendered expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); @@ -174,7 +205,7 @@ describe('', () => { expect(customOnEnd).not.toHaveBeenCalled(); }); - it('onClick of escape key disables tour', () => { + it('onClick of escape key disables tour', async () => { render( <> ', () => { expect(screen.getByRole('dialog', { name: 'Checkpoint 1' })).toBeInTheDocument(); // Click Escape key - fireEvent.keyDown(screen.getByRole('dialog'), { - key: 'Escape', - code: 'Escape', - keyCode: 27, - charCode: 27, - }); + await userEvent.keyboard('{escape}'); // Verify no Checkpoints have been rendered expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); @@ -253,8 +279,8 @@ describe('', () => { expect(screen.getByRole('heading', { name: 'Checkpoint 3' })).toBeInTheDocument(); }); - it('applies override for advanceButtonText', () => { - render( + it('applies override for advanceButtonText', async () => { + const { rerender } = render( <> ', () => { ); expect(screen.getByRole('button', { name: 'Override advance' })).toBeInTheDocument(); const advanceButton = screen.getByRole('button', { name: 'Override advance' }); - fireEvent.click(advanceButton); + await userEvent.click(advanceButton); expect(screen.queryByRole('button', { name: 'Override advance' })).not.toBeInTheDocument(); expect(customOnAdvance).toHaveBeenCalledTimes(1); + + rerender( + <> + + {targets} + , + ); + expect(screen.getByText('Checkpoint 4')).toBeInTheDocument(); }); it('applies override for dismissButtonText', () => { @@ -280,7 +316,7 @@ describe('', () => { ); expect(screen.getByRole('button', { name: 'Override dismiss' })).toBeInTheDocument(); }); - it('calls customHandleDismiss onClick of dismiss button', () => { + it('calls customHandleDismiss onClick of dismiss button', async () => { render( <> ', () => { , ); const dismissButton = screen.getByRole('button', { name: 'Override dismiss' }); - fireEvent.click(dismissButton); + await userEvent.click(dismissButton); expect(customOnDismiss).toHaveBeenCalledTimes(1); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); }); - it('calls customHandleOnEnd onClick of end button', () => { - render( + it('calls customHandleOnEnd onClick of end button', async () => { + const { rerender } = render( <> ', () => { , ); const advanceButton = screen.getByRole('button', { name: 'Override advance' }); - fireEvent.click(advanceButton); + await userEvent.click(advanceButton); + + rerender( + <> + + {targets} + , + ); + expect(screen.getByText('Checkpoint 4')).toBeInTheDocument(); const endButton = screen.getByRole('button', { name: 'Override end' }); - fireEvent.click(endButton); + await userEvent.click(endButton); expect(handleEnd).toBeCalledTimes(1); expect(customOnEnd).toHaveBeenCalledTimes(1); expect(screen.queryByText('Checkpoint 4')).not.toBeInTheDocument(); }); - it('calls onEscape on escape button key press', () => { + it('calls onEscape on escape button key press', async () => { render( <> ', () => { ); expect(screen.getByText('Checkpoint 3')).toBeInTheDocument(); const container = screen.getByRole('dialog'); - fireEvent.keyDown(container, { - key: 'Escape', - code: 'Escape', - keyCode: 27, - charCode: 27, - }); + container.focus(); + await userEvent.keyboard('{escape}'); expect(handleEscape).toHaveBeenCalledTimes(1); expect(screen.queryByText('Checkpoint 3')).not.toBeInTheDocument(); }); diff --git a/src/RadioButtonGroup/RadioButtonGroup.test.jsx b/src/RadioButtonGroup/RadioButtonGroup.test.jsx index 1102513e56..033c6eaf6f 100644 --- a/src/RadioButtonGroup/RadioButtonGroup.test.jsx +++ b/src/RadioButtonGroup/RadioButtonGroup.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import RadioButtonGroup, { RadioButton } from '.'; @@ -51,28 +52,30 @@ describe('', () => { spy.mockClear(); }); - it('should fire onBlur', () => { + it('should fire onBlur', async () => { render(()); const radioButton = screen.getByRole('radio'); - fireEvent.blur(radioButton); + radioButton.focus(); + await userEvent.tab(); expect(spy).toHaveBeenCalledTimes(1); }); - it('should fire onClick', () => { + it('should fire onClick', async () => { render(()); const radioButton = screen.getByRole('radio'); - fireEvent.click(radioButton); + await userEvent.click(radioButton); expect(spy).toHaveBeenCalledTimes(1); }); - it('should fire onFocus', () => { + it('should fire onFocus', async () => { render(()); const radioButton = screen.getByRole('radio'); - fireEvent.focus(radioButton); + radioButton.focus(); expect(spy).toHaveBeenCalledTimes(1); }); - it('should fire onKeyDown', () => { + it('should fire onKeyDown', async () => { render(()); const radioButton = screen.getByRole('radio'); - fireEvent.keyDown(radioButton); + radioButton.focus(); + await userEvent.keyboard('{enter}'); expect(spy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/SearchField/SearchField.test.jsx b/src/SearchField/SearchField.test.jsx index 1eb6e7da46..ac05fb5780 100644 --- a/src/SearchField/SearchField.test.jsx +++ b/src/SearchField/SearchField.test.jsx @@ -1,8 +1,14 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import SearchField from '.'; +const BUTTON_LOCATION_VARIANTS = [ + 'internal', + 'external', +]; + const baseProps = { onSubmit: () => {}, }; @@ -55,7 +61,7 @@ describe(' with basic usage', () => { expect(inputElement).toHaveValue(value); }); - it('should use passed in `screenReaderText` prop', () => { + it('should use passed in `screenReaderText` prop', async () => { const screenReaderText = { label: 'buscar', submitButton: 'enviar búsqueda', @@ -68,7 +74,7 @@ describe(' with basic usage', () => { expect(submitLabel).toBeInTheDocument(); const submitButton = screen.getByRole('button', { name: screenReaderText.submitButton, type: 'submit' }); expect(submitButton).toBeInTheDocument(); - fireEvent.change(input, { target: { value: 'foobar' } }); + await userEvent.type(input, 'foobar'); const resetButton = screen.getByRole('button', { name: screenReaderText.clearButton, type: 'reset' }); expect(resetButton).toBeInTheDocument(); }); @@ -86,77 +92,80 @@ describe(' with basic usage', () => { const props = { ...baseProps, onFocus: spy }; render(); const inputElement = screen.getByRole('searchbox'); - fireEvent.focus(inputElement); + inputElement.focus(); expect(spy).toHaveBeenCalledTimes(1); }); - it('blur handler', () => { + it('blur handler', async () => { const spy = jest.fn(); const props = { ...baseProps, onBlur: spy }; render(); const inputElement = screen.getByRole('searchbox'); - fireEvent.blur(inputElement); + inputElement.focus(); + await userEvent.tab(); expect(spy).toHaveBeenCalledTimes(1); }); - it('change handler', () => { + it('change handler', async () => { const spy = jest.fn(); const props = { ...baseProps, onChange: spy }; + const inputText = 'foobar'; render(); const inputElement = screen.getByRole('searchbox'); - fireEvent.change(inputElement, { target: { value: 'foobar' } }); - expect(spy).toHaveBeenCalledTimes(1); + await userEvent.type(inputElement, inputText); + expect(spy).toHaveBeenCalledTimes(inputText.length); }); - it('clear handler', () => { + it('clear handler', async () => { const spy = jest.fn(); const props = { ...baseProps, onClear: spy }; render(); const inputElement = screen.getByRole('searchbox'); - fireEvent.change(inputElement, { target: { value: 'foobar' } }); + await userEvent.type(inputElement, 'foobar'); const resetButton = screen.getByRole('button', { type: 'reset' }); - fireEvent.click(resetButton); + await userEvent.click(resetButton); expect(spy).toHaveBeenCalledTimes(1); }); - it('submit handler on submit button click', () => { + it('submit handler on submit button click', async () => { const spy = jest.fn(); - const props = { ...baseProps, onSubmit: spy }; + const props = { ...baseProps, onSubmit: spy, submitButtonLocation: BUTTON_LOCATION_VARIANTS[1] }; render(); + const inputElement = screen.getByRole('searchbox'); const submitButton = screen.getByRole('button', { type: 'submit' }); - fireEvent.change(submitButton, { target: { value: 'foobar' } }); - - fireEvent.click(submitButton); + await userEvent.type(inputElement, 'foobar'); + await userEvent.click(submitButton); expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('foobar'); }); }); describe('clear button', () => { - it('should be visible with input value', () => { + it('should be visible with input value', async () => { const props = { ...baseProps }; render(); const inputElement = screen.getByRole('searchbox'); expect(screen.queryByRole('button', { name: 'clear search', type: 'reset' })).toBeNull(); - fireEvent.change(inputElement, { target: { value: 'foobar' } }); + await userEvent.type(inputElement, 'foobar'); expect(screen.getByRole('button', { type: 'reset' })).toBeInTheDocument(); }); - it('should clear input value when clicked', () => { + it('should clear input value when clicked', async () => { const props = { ...baseProps }; render(); const inputElement = screen.getByRole('searchbox', { target: 'submit' }); - fireEvent.change(inputElement, { target: { value: 'foobar' } }); + await userEvent.type(inputElement, 'foobar'); expect(inputElement).toHaveValue('foobar'); const clearButton = screen.getByRole('button', { type: 'reset' }); - fireEvent.click(clearButton); + await userEvent.click(clearButton); expect(inputElement).toHaveValue(''); }); }); describe('advanced usage', () => { - it('should pass props to the clear button', () => { + it('should pass props to the clear button', async () => { const buttonProps = { variant: 'inline' }; render( @@ -165,7 +174,7 @@ describe(' with basic usage', () => { , ); const inputElement = screen.getByRole('searchbox'); - fireEvent.change(inputElement, { target: { value: 'foobar' } }); + await userEvent.type(inputElement, 'foobar'); const buttonClear = screen.getByRole('button', { type: 'reset', variant: buttonProps.variant }); expect(buttonClear).toHaveAttribute('variant', 'inline'); }); diff --git a/src/SearchField/__snapshots__/SearchField.test.jsx.snap b/src/SearchField/__snapshots__/SearchField.test.jsx.snap index c95aca1110..9cd5cf7612 100644 --- a/src/SearchField/__snapshots__/SearchField.test.jsx.snap +++ b/src/SearchField/__snapshots__/SearchField.test.jsx.snap @@ -6,7 +6,7 @@ exports[` with basic usage should match the snapshot 1`] = ` class="pgn__searchfield d-flex" >