From ac6c6061983bd63b69dbfa24e745b742b78a6cca Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Wed, 5 Oct 2022 10:34:11 +0200 Subject: [PATCH] Components: Refactor withFocusOutside to @testing-library/react --- .../with-focus-outside/test/index.js | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/packages/components/src/higher-order/with-focus-outside/test/index.js b/packages/components/src/higher-order/with-focus-outside/test/index.js index f310506f2d9dc4..feea9e8f2ff029 100644 --- a/packages/components/src/higher-order/with-focus-outside/test/index.js +++ b/packages/components/src/higher-order/with-focus-outside/test/index.js @@ -1,7 +1,8 @@ /** * External dependencies */ -import TestUtils from 'react-dom/test-utils'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; /** * WordPress dependencies @@ -12,9 +13,8 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ import withFocusOutside from '../'; -import ReactDOM from 'react-dom'; -let wrapper, onFocusOutside; +let onFocusOutside; describe( 'withFocusOutside', () => { let origHasFocus; @@ -28,7 +28,7 @@ describe( 'withFocusOutside', () => { render() { return (
- +
); @@ -36,24 +36,11 @@ describe( 'withFocusOutside', () => { } ); - // This is needed because TestUtils does not accept a stateless component. - // anything run through a HOC ends up as a stateless component. - const getTestComponent = ( WrappedComponent, props ) => { - class TestComponent extends Component { - render() { - return ; - } + class TestComponent extends Component { + render() { + return ; } - return ; - }; - - const simulateEvent = ( event, index = 0 ) => { - const element = TestUtils.scryRenderedDOMComponentsWithTag( - wrapper, - 'input' - ); - TestUtils.Simulate[ event ]( element[ index ] ); - }; + } beforeEach( () => { // Mock document.hasFocus() to always be true for testing @@ -62,9 +49,6 @@ describe( 'withFocusOutside', () => { document.hasFocus = () => true; onFocusOutside = jest.fn(); - wrapper = TestUtils.renderIntoDocument( - getTestComponent( EnhancedComponent, { onFocusOutside } ) - ); } ); afterEach( () => { @@ -72,24 +56,31 @@ describe( 'withFocusOutside', () => { } ); it( 'should not call handler if focus shifts to element within component', () => { - simulateEvent( 'focus' ); - simulateEvent( 'blur' ); - simulateEvent( 'focus', 1 ); + render( ); + + const input = screen.getByRole( 'textbox' ); + const button = screen.getByRole( 'button' ); + + input.focus(); + input.blur(); + button.focus(); jest.runAllTimers(); expect( onFocusOutside ).not.toHaveBeenCalled(); } ); - it( 'should not call handler if focus transitions via click to button', () => { - simulateEvent( 'focus' ); - simulateEvent( 'mouseDown', 1 ); - simulateEvent( 'blur' ); + it( 'should not call handler if focus transitions via click to button', async () => { + const user = userEvent.setup( { + advanceTimers: jest.advanceTimersByTime, + } ); + render( ); - // In most browsers, the input at index 1 would receive a focus event - // at this point, but this is not guaranteed, which is the intention of - // the normalization behavior tested here. - simulateEvent( 'mouseUp', 1 ); + const input = screen.getByRole( 'textbox' ); + const button = screen.getByRole( 'button' ); + + input.focus(); + await user.click( button ); jest.runAllTimers(); @@ -97,8 +88,11 @@ describe( 'withFocusOutside', () => { } ); it( 'should call handler if focus doesn’t shift to element within component', () => { - simulateEvent( 'focus' ); - simulateEvent( 'blur' ); + render( ); + + const input = screen.getByRole( 'textbox' ); + input.focus(); + input.blur(); jest.runAllTimers(); @@ -106,12 +100,15 @@ describe( 'withFocusOutside', () => { } ); it( 'should not call handler if focus shifts outside the component when the document does not have focus', () => { + render( ); + // Force document.hasFocus() to return false to simulate the window/document losing focus // See https://developer.mozilla.org/en-US/docs/Web/API/Document/hasFocus. document.hasFocus = () => false; - simulateEvent( 'focus' ); - simulateEvent( 'blur' ); + const input = screen.getByRole( 'textbox' ); + input.focus(); + input.blur(); jest.runAllTimers(); @@ -119,14 +116,16 @@ describe( 'withFocusOutside', () => { } ); it( 'should cancel check when unmounting while queued', () => { - simulateEvent( 'focus' ); - simulateEvent( 'input' ); - - ReactDOM.unmountComponentAtNode( - // eslint-disable-next-line react/no-find-dom-node - ReactDOM.findDOMNode( wrapper ).parentNode + const { rerender } = render( + ); + const input = screen.getByRole( 'textbox' ); + input.focus(); + input.blur(); + + rerender(
); + jest.runAllTimers(); expect( onFocusOutside ).not.toHaveBeenCalled();