From 30d67e84ab12783f90f33b419bace2b1ddb93035 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Wed, 5 Oct 2022 12:13:01 +0200 Subject: [PATCH] Components: Refactor useFocusOutside to @testing-library/react (#44698) --- .../src/hooks/use-focus-outside/test/index.js | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/packages/compose/src/hooks/use-focus-outside/test/index.js b/packages/compose/src/hooks/use-focus-outside/test/index.js index 23c7c36cf43e3..093bbb09ed1b3 100644 --- a/packages/compose/src/hooks/use-focus-outside/test/index.js +++ b/packages/compose/src/hooks/use-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,38 +13,24 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ import useFocusOutside from '../'; -import ReactDOM from 'react-dom'; -let wrapper, onFocusOutside; +let onFocusOutside; describe( 'useFocusOutside', () => { let origHasFocus; const FocusOutsideComponent = ( { onFocusOutside: callback } ) => (
- +
); - // 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 @@ -52,9 +39,6 @@ describe( 'useFocusOutside', () => { document.hasFocus = () => true; onFocusOutside = jest.fn(); - wrapper = TestUtils.renderIntoDocument( - getTestComponent( FocusOutsideComponent, { onFocusOutside } ) - ); } ); afterEach( () => { @@ -62,24 +46,31 @@ describe( 'useFocusOutside', () => { } ); 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( ); + + const input = screen.getByRole( 'textbox' ); + const button = screen.getByRole( 'button' ); - // 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 ); + input.focus(); + await user.click( button ); jest.runAllTimers(); @@ -87,8 +78,11 @@ describe( 'useFocusOutside', () => { } ); 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(); @@ -96,12 +90,15 @@ describe( 'useFocusOutside', () => { } ); 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(); @@ -109,14 +106,16 @@ describe( 'useFocusOutside', () => { } ); 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();