diff --git a/UNRELEASED.md b/UNRELEASED.md index 18f33c0cc6b..78527298188 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -19,4 +19,6 @@ ### Code quality +- Migrated tests using document.activeElement to use react-testing ([#3070](https://github.com/Shopify/polaris-react/pull/3070)) + ### Deprecations diff --git a/src/components/Banner/tests/Banner.test.tsx b/src/components/Banner/tests/Banner.test.tsx index 48200bdf95a..b46c5c5a58f 100644 --- a/src/components/Banner/tests/Banner.test.tsx +++ b/src/components/Banner/tests/Banner.test.tsx @@ -145,11 +145,11 @@ describe('', () => { return ; } - const div = mountWithAppProvider() - .find('div') - .filterWhere((element) => element.prop('tabIndex') === 0); + const testComponent = mountWithApp(); - expect(div.getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe( + testComponent.find('div', {tabIndex: 0})!.domNode, + ); }); describe('Focus className', () => { diff --git a/src/components/Checkbox/tests/Checkbox.test.tsx b/src/components/Checkbox/tests/Checkbox.test.tsx index 35083c8f623..37817273eb1 100644 --- a/src/components/Checkbox/tests/Checkbox.test.tsx +++ b/src/components/Checkbox/tests/Checkbox.test.tsx @@ -4,6 +4,7 @@ import {mountWithAppProvider} from 'test-utilities/legacy'; import {mountWithApp} from 'test-utilities'; import {Key} from '../../../types'; +import {Choice} from '../../Choice'; import {Checkbox} from '../Checkbox'; describe('', () => { @@ -73,12 +74,12 @@ describe('', () => { }); it('sets focus on the input when checkbox is toggled off', () => { - const checkbox = mountWithAppProvider( + const checkbox = mountWithApp( , ); - (checkbox.find('input') as any).instance().checked = false; - checkbox.simulate('click'); - expect(checkbox.find('input').instance()).toBe(document.activeElement); + checkbox.find(Choice)!.trigger('onClick'); + + expect(document.activeElement).toBe(checkbox.find('input')!.domNode); }); it('is not called from keyboard events when disabled', () => { diff --git a/src/components/Focus/tests/Focus.test.tsx b/src/components/Focus/tests/Focus.test.tsx index 4d0a9251928..62ac9911071 100644 --- a/src/components/Focus/tests/Focus.test.tsx +++ b/src/components/Focus/tests/Focus.test.tsx @@ -1,68 +1,57 @@ import React, {useRef, useState, useEffect} from 'react'; -// eslint-disable-next-line no-restricted-imports -import {mountWithAppProvider} from 'test-utilities/legacy'; +import {mountWithApp} from 'test-utilities'; import {Focus, FocusProps} from '../Focus'; describe('', () => { - it('mounts', () => { - const focus = mountWithAppProvider(); - - expect(focus.exists()).toBe(true); - }); - it('will not focus any element if none are natively focusable', () => { - mountWithAppProvider( + mountWithApp( , ); - expect(document.body).toBe(document.activeElement); + expect(document.activeElement).toBe(document.body); }); it('will focus first focusable node when passing current node', () => { - const focus = mountWithAppProvider( + const focus = mountWithApp( , ); - const input = focus.find('input').getDOMNode(); - expect(input).toBe(document.activeElement); + expect(document.activeElement).toBe(focus.find('input')!.domNode); }); it('will focus first focusable node when passing ref', () => { - const focus = mountWithAppProvider( + const focus = mountWithApp( , ); - const input = focus.find('input').getDOMNode(); - expect(input).toBe(document.activeElement); + expect(document.activeElement).toBe(focus.find('input')!.domNode); }); it('will not focus the first focusable node if `disabled` is true', () => { - const focus = mountWithAppProvider( + const focus = mountWithApp( , ); - const input = focus.find('input').getDOMNode(); - expect(input).not.toBe(document.activeElement); + expect(document.activeElement).not.toBe(focus.find('input')!.domNode); }); it('will not focus if there is no node', () => { - const focus = mountWithAppProvider( + const focus = mountWithApp( , ); - const input = focus.find('input').getDOMNode(); - expect(input).not.toBe(document.activeElement); + expect(document.activeElement).not.toBe(focus.find('input')!.domNode); }); }); diff --git a/src/components/Frame/tests/Frame.test.tsx b/src/components/Frame/tests/Frame.test.tsx index 16beb27091c..a4f3e1f7569 100644 --- a/src/components/Frame/tests/Frame.test.tsx +++ b/src/components/Frame/tests/Frame.test.tsx @@ -3,7 +3,7 @@ import {CSSTransition} from '@material-ui/react-transition-group'; import {animationFrame} from '@shopify/jest-dom-mocks'; import {documentHasStyle, mountWithApp} from 'test-utilities'; // eslint-disable-next-line no-restricted-imports -import {mountWithAppProvider, trigger} from 'test-utilities/legacy'; +import {mountWithAppProvider} from 'test-utilities/legacy'; import { ContextualSaveBar as PolarisContextualSavebar, Loading as PolarisLoading, @@ -53,10 +53,12 @@ describe('', () => { }); it('sets focus to the main content target anchor element when the skip to content link is clicked', () => { - const frame = mountWithAppProvider(); - const mainAnchor = frame.find('main').find('a'); - trigger(frame.find('a').at(0), 'onClick'); - expect(mainAnchor.getDOMNode()).toBe(document.activeElement); + const frame = mountWithApp(); + + frame.find('a', {children: 'Skip to content'})!.trigger('onClick'); + expect(document.activeElement).toBe( + frame.find('a', {id: 'AppFrameMainContent'})!.domNode, + ); }); it('sets focus to target element when the skip to content link is clicked', () => { @@ -68,19 +70,18 @@ describe('', () => { ); - const frame = mountWithAppProvider( + const frame = mountWithApp( {skipToContentTarget}, ); - const triggerAnchor = frame.find('a').at(0); - const targetAnchor = frame.find(`#${targetId}`); - trigger(triggerAnchor, 'onFocus'); - trigger(triggerAnchor, 'onClick'); + const triggerAnchor = frame.findAll('a')[0]!; + + triggerAnchor.trigger('onFocus'); + triggerAnchor.trigger('onClick'); - expect(triggerAnchor.getDOMNode().getAttribute('href')).toBe( - `#${targetId}`, + expect(document.activeElement).toBe( + frame.find('a', {id: targetId})!.domNode, ); - expect(targetAnchor.getDOMNode()).toBe(document.activeElement); }); }); diff --git a/src/components/Modal/tests/Modal.test.tsx b/src/components/Modal/tests/Modal.test.tsx index abebfe01618..bff70784b6a 100644 --- a/src/components/Modal/tests/Modal.test.tsx +++ b/src/components/Modal/tests/Modal.test.tsx @@ -58,7 +58,7 @@ describe('', () => { const modal = mountWithAppProvider(); const focusedNode = findFirstFocusableNode(modal.find(Dialog).getDOMNode()); - expect(focusedNode).toBe(document.activeElement); + expect(document.activeElement).toBe(focusedNode); }); describe('src', () => { diff --git a/src/components/ResourceList/components/FilterControl/components/FilterCreator/tests/FilterCreator.test.tsx b/src/components/ResourceList/components/FilterControl/components/FilterCreator/tests/FilterCreator.test.tsx index 197ed4cde79..fcd404d4008 100644 --- a/src/components/ResourceList/components/FilterControl/components/FilterCreator/tests/FilterCreator.test.tsx +++ b/src/components/ResourceList/components/FilterControl/components/FilterCreator/tests/FilterCreator.test.tsx @@ -87,7 +87,7 @@ describe('', () => { 'onClick', ); - expect(activator.getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(activator.getDOMNode()); }); it('does not focus the activator after adding a filter if focus was never originally received by the by activator', () => { @@ -110,7 +110,7 @@ describe('', () => { 'onClick', ); - expect(activator.getDOMNode()).not.toBe(document.activeElement); + expect(document.activeElement).not.toBe(activator.getDOMNode()); }); it('renders just a button by default', () => { diff --git a/src/components/ResourceList/tests/ResourceList.test.tsx b/src/components/ResourceList/tests/ResourceList.test.tsx index da4eed90db2..c3d4beb3f95 100644 --- a/src/components/ResourceList/tests/ResourceList.test.tsx +++ b/src/components/ResourceList/tests/ResourceList.test.tsx @@ -9,12 +9,12 @@ import { Button, EmptyState, } from 'components'; +import {mountWithApp} from 'test-utilities'; // eslint-disable-next-line no-restricted-imports import { findByTestID, mountWithAppProvider, trigger, - ReactWrapper, } from 'test-utilities/legacy'; import {BulkActions, CheckableButton} from '../components'; @@ -925,7 +925,7 @@ describe('', () => { describe('large screen', () => { it('focuses the checkbox in the bulk action when the plain CheckableButton is clicked', () => { - const resourceList = mountWithAppProvider( + const resourceList = mountWithApp( ', () => { />, ); - const selectAllCheckableButton = plainCheckableButton(resourceList); + resourceList + .find(CheckableButton, {plain: true})! + .trigger('onToggleAll'); - trigger(selectAllCheckableButton, 'onToggleAll'); + const deselectAllCheckbox = resourceList + .findAll(CheckableButton) + .find((ele) => !ele.prop('plain'))! + .find('input', {type: 'checkbox'})!; - const deselectAllCheckbox = bulkActionsCheckableButton( - resourceList, - ).find('input[type="checkbox"]'); - - expect(deselectAllCheckbox.getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(deselectAllCheckbox.domNode); }); it('focuses the plain CheckableButton checkbox when items are selected and the deselect Checkable button is clicked', () => { - const resourceList = mountWithAppProvider( + const resourceList = mountWithApp( ', () => { />, ); - const deselectAllCheckableButton = bulkActionsCheckableButton( - resourceList, - ); - - trigger(deselectAllCheckableButton, 'onToggleAll'); + resourceList + .findAll(CheckableButton) + .find((ele) => !ele.prop('plain'))! + .trigger('onToggleAll'); - const selectAllCheckableCheckbox = plainCheckableButton( - resourceList, - ).find('input[type="checkbox"]'); + const selectAllCheckableCheckbox = resourceList + .find(CheckableButton, {plain: true})! + .find('input', {type: 'checkbox'})!; - expect(selectAllCheckableCheckbox.getDOMNode()).toBe( - document.activeElement, + expect(document.activeElement).toBe( + selectAllCheckableCheckbox.domNode, ); }); }); @@ -978,7 +978,7 @@ describe('', () => { it('keeps focus on the CheckableButton checkbox when selecting', () => { setSmallScreen(); - const resourceList = mountWithAppProvider( + const resourceList = mountWithApp( ', () => { />, ); - trigger(resourceList.find(Button).first(), 'onClick'); + resourceList.find(Button)!.trigger('onClick'); - const selectAllCheckableButton = bulkActionsCheckableButton( - resourceList, - ); + const selectAllCheckableButton = resourceList + .findAll(CheckableButton) + .find((ele) => !ele.prop('plain'))!; - trigger(selectAllCheckableButton, 'onToggleAll'); + selectAllCheckableButton.trigger('onToggleAll'); - const checkBox = selectAllCheckableButton.find( - 'input[type="checkbox"]', - ); + const checkBox = selectAllCheckableButton.find('input', { + type: 'checkbox', + })!; - expect(checkBox.getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(checkBox.domNode); }); it('keeps focus on the CheckableButton checkbox when deselecting', () => { setSmallScreen(); - const resourceList = mountWithAppProvider( + const resourceList = mountWithApp( ', () => { />, ); - const deselectAllCheckableButton = bulkActionsCheckableButton( - resourceList, - ); + const deselectAllCheckableButton = resourceList + .findAll(CheckableButton) + .find((ele) => !ele.prop('plain'))!; - trigger(deselectAllCheckableButton, 'onToggleAll'); + deselectAllCheckableButton.trigger('onToggleAll'); - const checkBox = deselectAllCheckableButton.find( - 'input[type="checkbox"]', - ); + const checkBox = deselectAllCheckableButton.find('input', { + type: 'checkbox', + })!; - expect(checkBox.getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(checkBox.domNode); }); }); }); @@ -1224,15 +1224,3 @@ function setDefaultScreen() { value: defaultWindowWidth, }); } - -function bulkActionsCheckableButton(wrapper: ReactWrapper) { - return wrapper.findWhere( - (wrap) => wrap.is(CheckableButton) && !wrap.prop('plain'), - ); -} - -function plainCheckableButton(wrapper: ReactWrapper) { - return wrapper.findWhere( - (wrap) => wrap.is(CheckableButton) && wrap.prop('plain'), - ); -} diff --git a/src/components/TextField/tests/TextField.test.tsx b/src/components/TextField/tests/TextField.test.tsx index a7f83c81aa8..5ef872a0a7e 100644 --- a/src/components/TextField/tests/TextField.test.tsx +++ b/src/components/TextField/tests/TextField.test.tsx @@ -1,4 +1,4 @@ -import React, {ReactElement} from 'react'; +import React from 'react'; // eslint-disable-next-line no-restricted-imports import {mountWithAppProvider, findByTestID} from 'test-utilities/legacy'; import {InlineError, Labelled, Connected, Select} from 'components'; @@ -85,11 +85,11 @@ describe('', () => { describe('onFocus()', () => { it('is called when the input is focused', () => { const spy = jest.fn(); - mountWithAppProvider( + mountWithApp( , ) - .find('input') - .simulate('focus'); + .find('input')! + .trigger('onFocus'); expect(spy).toHaveBeenCalled(); }); }); @@ -147,37 +147,31 @@ describe('', () => { describe('focused', () => { it('input is in focus state if focused is true', () => { - const element = mountWithAppProvider( + const element = mountWithApp( , ); - expect(element.getDOMNode().querySelector('input')).toBe( - document.activeElement, - ); + expect(document.activeElement).toBe(element.find('input')!.domNode); }); it('focuses input if focused is toggled', () => { - const element = mountWithAppProvider( + const element = mountWithApp( , ); element.setProps({focused: true}); - expect(element.getDOMNode().querySelector('input')).toBe( - document.activeElement, - ); + expect(document.activeElement).toBe(element.find('input')!.domNode); }); it('blurs input if focused is toggled', () => { - const element = mountWithAppProvider( + const element = mountWithApp( , ); element.setProps({focused: false}); - expect(element.getDOMNode().querySelector('input')).not.toBe( - document.activeElement, - ); + expect(document.activeElement).not.toBe(element.find('input')!.domNode); }); }); @@ -1034,22 +1028,15 @@ describe('', () => { }); it('sets focus to the `onClick`', () => { - const textField = mountWithAppProvider( + const textField = mountWithApp( , ); - const connectedChild = textField - .find(Connected) - .prop('children') as ReactElement; - expect(textField.getDOMNode().querySelector('input')).not.toBe( - document.activeElement, - ); + expect(document.activeElement).not.toBe(textField.find('input')!.domNode); - connectedChild.props.onClick({}); + textField.find(Connected)!.triggerKeypath('children.props.onClick', {}); - expect(textField.getDOMNode().querySelector('input')).toBe( - document.activeElement, - ); + expect(document.activeElement).toBe(textField.find('input')!.domNode); }); }); diff --git a/src/components/TopBar/components/SearchField/tests/SearchField.test.tsx b/src/components/TopBar/components/SearchField/tests/SearchField.test.tsx index 13b7acd83e4..25844365835 100644 --- a/src/components/TopBar/components/SearchField/tests/SearchField.test.tsx +++ b/src/components/TopBar/components/SearchField/tests/SearchField.test.tsx @@ -1,20 +1,12 @@ import React from 'react'; import {CircleCancelMinor} from '@shopify/polaris-icons'; +import {mountWithApp} from 'test-utilities'; // eslint-disable-next-line no-restricted-imports import {mountWithAppProvider, ReactWrapper} from 'test-utilities/legacy'; -import {mountWithApp} from 'test-utilities'; import {SearchField} from '../SearchField'; -describe('', () => { - it('mounts', () => { - const textField = mountWithAppProvider( - , - ); - - expect(textField.exists()).toBe(true); - }); - +describe('', () => { it('passes the placeholder prop to input', () => { const textField = mountWithAppProvider( , @@ -25,33 +17,31 @@ describe('', () => { describe('focused', () => { it('will give input focus when the focused prop is true', () => { - const textField = mountWithAppProvider( + const textField = mountWithApp( , ); - expect(findInput(textField).getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(textField.find('input')!.domNode); }); it('will give input focus if focus has been toggled', () => { - const textField = mountWithAppProvider( + const textField = mountWithApp( , ); - expect(findInput(textField).getDOMNode()).not.toBe( - document.activeElement, - ); + + expect(document.activeElement).not.toBe(textField.find('input')!.domNode); + textField.setProps({value: '', onChange: noop, focused: true}); - expect(findInput(textField).getDOMNode()).toBe(document.activeElement); + expect(document.activeElement).toBe(textField.find('input')!.domNode); }); it('will blur input if focused has been toggled', () => { - const textField = mountWithAppProvider( + const textField = mountWithApp( , ); textField.setProps({value: '', onChange: noop, focused: false}); - expect(findInput(textField).getDOMNode()).not.toBe( - document.activeElement, - ); + expect(document.activeElement).not.toBe(textField.find('input')!.domNode); }); }); diff --git a/src/components/TrapFocus/tests/TrapFocus.test.tsx b/src/components/TrapFocus/tests/TrapFocus.test.tsx index 31d1e85fa44..6c8eafb57c2 100644 --- a/src/components/TrapFocus/tests/TrapFocus.test.tsx +++ b/src/components/TrapFocus/tests/TrapFocus.test.tsx @@ -1,10 +1,4 @@ import React from 'react'; -// eslint-disable-next-line no-restricted-imports -import { - mountWithAppProvider, - trigger, - ReactWrapper, -} from 'test-utilities/legacy'; import {mountWithApp} from 'test-utilities'; import { EventListener, @@ -54,75 +48,73 @@ describe('', () => { }); it('mounts', () => { - const trapFocus = mountWithAppProvider( + const trapFocus = mountWithApp( Test , ); - expect(trapFocus.exists()).toBe(true); - // Render children - expect(trapFocus.find(TextContainer)).toHaveLength(1); + expect(trapFocus).toContainReactComponent(TextContainer); // Renders Focus - expect(trapFocus.find(Focus)).toHaveLength(1); + expect(trapFocus).toContainReactComponent(Focus); // Renders an event listener - expect(trapFocus.find(EventListener)).toHaveLength(1); - expect(trapFocus.find(EventListener).prop('event')).toBe('focusin'); + expect(trapFocus).toContainReactComponent(EventListener, { + event: 'focusin', + }); }); it('renders a Focus component with a `disabled` prop set to false by default', () => { - const focus = mountWithAppProvider( + const trapFocus = mountWithApp(
, - ).find(Focus); - expect(focus.prop('disabled')).toBe(false); + ); + expect(trapFocus).toContainReactComponent(Focus, {disabled: false}); }); it('renders a Focus component with a `disabled` prop set to true when `trapping` is false', () => { - const focus = mountWithAppProvider( + const trapFocus = mountWithApp(
, - ).find(Focus); + ); - expect(focus.prop('disabled')).toBe(true); + expect(trapFocus).toContainReactComponent(Focus, {disabled: true}); }); it('renders a Focus component with a `disabled` prop set to false when `trapping` is true', () => { - const focus = mountWithAppProvider( + const trapFocus = mountWithApp(
, - ).find(Focus); + ); - expect(focus.prop('disabled')).toBe(false); + expect(trapFocus).toContainReactComponent(Focus, {disabled: false}); }); it('keeps focus on nodes contained inside trap focus during mount', () => { - const trapFocus = mountWithAppProvider( + const trapFocus = mountWithApp( , ); - const input = trapFocus.find('input').getDOMNode(); - expect(document.activeElement).toBe(input); + + expect(document.activeElement).toBe(trapFocus.find('input')!.domNode); }); it('focuses the first focused node when nodes contained in trap focus are not in focus', () => { - const trapFocus = mountWithAppProvider( + const trapFocus = mountWithApp( , ); - const focusedElement = trapFocus.find('a').getDOMNode(); - expect(document.activeElement).toBe(focusedElement); + expect(document.activeElement).toBe(trapFocus.find('a')!.domNode); }); it(`doesn't trade steal focus from another TrapFocus when multiple are rendered`, () => { @@ -138,13 +130,11 @@ describe('', () => {
, ); - expect(trapFocus.find('input', {id})!.domNode).toBe(document.activeElement); + expect(document.activeElement).toBe(trapFocus.find('input', {id})!.domNode); }); describe('handleBlur', () => { - const externalDomNode = mountWithAppProvider(