From 8603386a807dbae8d57b8d02d735e60e002947b4 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 8 Aug 2022 20:46:02 +0900 Subject: [PATCH 01/24] Migrate frim enzyme to testing-library --- packages/components/src/tooltip/test/index.js | 159 ++++++++---------- 1 file changed, 74 insertions(+), 85 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 4935809ee6329..dc65bb217127d 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { shallow, mount } from 'enzyme'; +import { fireEvent, render, screen } from '@testing-library/react'; /** * Internal dependencies @@ -11,60 +11,57 @@ import Tooltip from '../'; * WordPress dependencies */ import { TOOLTIP_DELAY } from '../index.js'; -import { act } from '@testing-library/react'; describe( 'Tooltip', () => { describe( '#render()', () => { it( 'should render children (abort) if multiple children passed', () => { - // Mount: Enzyme shallow does not support wrapping multiple nodes. - const wrapper = mount( + const { container } = render(
); - expect( wrapper.children() ).toHaveLength( 2 ); + expect( container.children ).toHaveLength( 2 ); } ); it( 'should render children', () => { - const wrapper = shallow( + render( ); - const button = wrapper.find( 'button' ); - expect( wrapper.type() ).toBe( 'button' ); - expect( button.children() ).toHaveLength( 1 ); - expect( button.childAt( 0 ).text() ).toBe( 'Hover Me!' ); + const button = screen.getByRole( 'button' ); + expect( button.nodeName ).toBe( 'BUTTON' ); + expect( button.childNodes ).toHaveLength( 1 ); + expect( button.textContent ).toBe( 'Hover Me!' ); } ); it( 'should render children with additional popover when over', () => { - const wrapper = shallow( + const { container } = render( ); - const event = { type: 'focus', currentTarget: {} }; - wrapper.simulate( 'focus', event ); + const button = screen.getByRole( 'button' ); + button.focus(); - const button = wrapper.find( 'button' ); - const popover = wrapper.find( 'ForwardRef(Popover)' ); - expect( wrapper.type() ).toBe( 'button' ); - expect( button.children() ).toHaveLength( 2 ); - expect( button.childAt( 0 ).text() ).toBe( 'Hover Me!' ); - expect( button.childAt( 1 ).name() ).toBe( 'ForwardRef(Popover)' ); - expect( popover.prop( 'focusOnMount' ) ).toBe( false ); - expect( popover.prop( 'position' ) ).toBe( 'bottom right' ); - expect( popover.children().first().text() ).toBe( 'Help text' ); + const popover = + container.getElementsByClassName( 'components-popover' ); + expect( button.nodeName ).toBe( 'BUTTON' ); + expect( button.childNodes ).toHaveLength( 2 ); + expect( button.childNodes[ 0 ].textContent ).toBe( 'Hover Me!' ); + expect( button.childNodes[ 1 ] ).toHaveClass( + 'components-popover' + ); + expect( popover[ 0 ].firstChild.textContent ).toBe( 'Help text' ); } ); it( 'should show popover on focus', () => { const originalFocus = jest.fn(); - const event = { type: 'focus', currentTarget: {} }; - const wrapper = shallow( + const { container } = render( ); - const button = wrapper.find( 'button[disabled]' ); - const buttonNode = button.at( 0 ).getDOMNode(); - const buttonRect = buttonNode.getBoundingClientRect(); - const eventCatcher = wrapper.find( '.event-catcher' ); - const eventCatcherNode = eventCatcher.at( 0 ).getDOMNode(); - const eventCatcherRect = eventCatcherNode.getBoundingClientRect(); + + const button = screen.getByRole( 'button' ); + const buttonRect = button.getBoundingClientRect(); + const eventCatcher = + container.getElementsByClassName( 'event-catcher' )[ 0 ]; + const eventCatcherRect = eventCatcher.getBoundingClientRect(); expect( buttonRect ).toEqual( eventCatcherRect ); - eventCatcher.simulate( 'mouseenter', { - type: 'mouseenter', - currentTarget: {}, - } ); + fireEvent.mouseOver( eventCatcher ); setTimeout( () => { - const popover = wrapper.find( 'Popover' ); + const popover = + container.getElementsByClassName( 'components-popover' ); expect( popover ).toHaveLength( 1 ); }, TOOLTIP_DELAY ); } ); it( 'should not emit events back to children when they are disabled', () => { const handleClick = jest.fn(); - - const wrapper = mount( + const { container } = render( @@ -201,7 +222,7 @@ describe( 'Tooltip', () => { const eventCatcherRect = eventCatcher.getBoundingClientRect(); expect( buttonRect ).toEqual( eventCatcherRect ); - fireEvent.mouseOver( eventCatcher ); + await user.hover( eventCatcher ); setTimeout( () => { const popover = @@ -210,7 +231,11 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should not emit events back to children when they are disabled', () => { + it( 'should not emit events back to children when they are disabled', async () => { + const user = userEvent.setup( { + advanceTimers: jest.advanceTimersByTime, + } ); + const handleClick = jest.fn(); const { container } = render( @@ -222,11 +247,15 @@ describe( 'Tooltip', () => { const eventCatcher = container.getElementsByClassName( 'event-catcher' )[ 0 ]; - fireEvent.click( eventCatcher ); + await user.click( eventCatcher ); expect( handleClick ).not.toHaveBeenCalled(); } ); - it( 'should cancel pending setIsOver on mouseleave', () => { + it( 'should cancel pending setIsOver on mouseleave', async () => { + const user = userEvent.setup( { + advanceTimers: jest.advanceTimersByTime, + } ); + const originalMouseEnter = jest.fn(); const { container } = render( @@ -240,7 +269,7 @@ describe( 'Tooltip', () => { ); const button = screen.getByRole( 'button' ); - fireEvent.mouseOver( button ); + await user.hover( button ); setTimeout( () => { const popover = container.getElementsByClassName( 'components-popover' ); From 28b1abecfc25ebe895dabdad9ecbe63a3fdb1b26 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Fri, 12 Aug 2022 19:11:43 +0900 Subject: [PATCH 06/24] Brush up test (tooltip won't be rendered) --- packages/components/src/tooltip/test/index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index d9588edaed037..ec3c8f62289f1 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -16,14 +16,16 @@ import { TOOLTIP_DELAY } from '../index.js'; describe( 'Tooltip', () => { describe( '#render()', () => { it( 'should render children (abort) if multiple children passed', () => { - const { container } = render( - -
-
+ render( + + + ); - expect( container.children ).toHaveLength( 2 ); + const button = screen.getByText( 'Button 1' ); + button.focus(); + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); } ); it( 'should render children', () => { From 10274ad0dcb08307827e6e102d6795749e2f493e Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Fri, 12 Aug 2022 19:51:39 +0900 Subject: [PATCH 07/24] Refactor setTimeout to findBy in one test --- packages/components/src/tooltip/test/index.js | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index ec3c8f62289f1..5bd64566c6428 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -135,8 +135,7 @@ describe( 'Tooltip', () => { } ); const originalMouseEnter = jest.fn(); - jest.useFakeTimers(); - const { container } = render( + render( @@ -53,16 +53,12 @@ describe( 'Tooltip', () => { expect( button.nodeName ).toBe( 'BUTTON' ); expect( button.childNodes ).toHaveLength( 2 ); expect( button.childNodes[ 0 ] ).toHaveTextContent( 'Hover Me!' ); - - const popover = - container.getElementsByClassName( 'components-popover' ); - expect( popover ).toHaveLength( 1 ); - expect( popover[ 0 ].firstChild ).toHaveTextContent( 'Help text' ); + expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); } ); it( 'should show popover on focus', () => { const originalFocus = jest.fn(); - const { container } = render( + render( + ); From 3126a88bda661681ed61acc7e795eb264a7eae0d Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 15 Aug 2022 20:43:34 +0900 Subject: [PATCH 11/24] Remove tootip position props --- packages/components/src/tooltip/test/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 0156b69435952..2d32f1b480222 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -17,7 +17,7 @@ describe( 'Tooltip', () => { describe( '#render()', () => { it( 'should render children (abort) if multiple children passed', () => { render( - + @@ -30,7 +30,7 @@ describe( 'Tooltip', () => { it( 'should render children', () => { render( - + ); @@ -42,7 +42,7 @@ describe( 'Tooltip', () => { it( 'should render children with additional popover when over', () => { render( - + ); From 4e9b4cf904dae6246904b32f1e40bcf21e69e48c Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 15 Aug 2022 21:30:17 +0900 Subject: [PATCH 12/24] Add test: should render children with additional popover when hovered --- packages/components/src/tooltip/test/index.js | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 2d32f1b480222..c6807d12b156d 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -40,7 +40,7 @@ describe( 'Tooltip', () => { ).toBeInTheDocument(); } ); - it( 'should render children with additional popover when over', () => { + it( 'should render children with additional popover when focused', () => { render( @@ -55,6 +55,32 @@ describe( 'Tooltip', () => { expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); } ); + it( 'should render children with additional popover when hovered', async () => { + const user = userEvent.setup( { + advanceTimers: jest.advanceTimersByTime, + } ); + jest.useFakeTimers(); + + render( + + + + ); + + const button = screen.getByRole( 'button' ); + await user.hover( button ); + + expect( + screen.getByRole( 'button', { name: 'Hover Me!' } ) + ).toBeInTheDocument(); + + setTimeout( () => { + expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); + jest.runOnlyPendingTimers(); + jest.useRealTimers(); + }, TOOLTIP_DELAY ); + } ); + it( 'should show popover on focus', () => { const originalFocus = jest.fn(); render( @@ -120,6 +146,7 @@ describe( 'Tooltip', () => { } ); const originalMouseEnter = jest.fn(); + jest.useFakeTimers(); render( + ); const button = screen.getByRole( 'button' ); - // Hovers the button and press the left mouse button - await user.pointer( [ - { target: button }, - { keys: '[MouseLeft]', target: button }, - ] ); - expect( originalOnMouseDown ).toHaveBeenCalledWith( - expect.objectContaining( { - type: 'mousedown', - } ) - ); - - expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); - - // Release the left mouse button - await user.pointer( [ { keys: '[/MouseLeft]', target: button } ] ); - expect( originalOnMouseUp ).toHaveBeenCalledWith( - expect.objectContaining( { - type: 'mouseup', - } ) - ); + await user.click( button ); + setTimeout( () => { + expect( + screen.queryByText( 'Help text' ) + ).not.toBeInTheDocument(); + jest.runOnlyPendingTimers(); + jest.useRealTimers(); + }, TOOLTIP_DELAY ); } ); it( 'should show popover on delayed mouseenter', async () => { From 7aa6669671ee741dd9027c2ff6747ce6b2d3c0f2 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 16:51:25 +0900 Subject: [PATCH 14/24] Standardize test cases name --- packages/components/src/tooltip/test/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 81feed08046fc..82ef24b783845 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -15,7 +15,7 @@ import { TOOLTIP_DELAY } from '../index.js'; describe( 'Tooltip', () => { describe( '#render()', () => { - it( 'should render children (abort) if multiple children passed', () => { + it( 'should not render the tooltip if multiple children are passed', () => { render( @@ -40,7 +40,7 @@ describe( 'Tooltip', () => { ).toBeInTheDocument(); } ); - it( 'should render children with additional popover when focused', () => { + it( 'should render children with additional tooltip when focused', () => { render( @@ -55,7 +55,7 @@ describe( 'Tooltip', () => { expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); } ); - it( 'should render children with additional popover when hovered', async () => { + it( 'should render children with additional tooltip when hovered', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); @@ -81,7 +81,7 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should show popover on focus', () => { + it( 'should show tooltip on focus', () => { const originalFocus = jest.fn(); render( @@ -99,7 +99,7 @@ describe( 'Tooltip', () => { expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); } ); - it( 'should not show popover on focus as result of mouse click', async () => { + it( 'should not show tooltip on focus as result of mouse click', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); @@ -122,7 +122,7 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should show popover on delayed mouseenter', async () => { + it( 'should show tooltip on delayed mouseenter', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); @@ -152,7 +152,7 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should respect custom delay prop when showing popover', async () => { + it( 'should respect custom delay prop when showing tooltip', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); @@ -175,13 +175,13 @@ describe( 'Tooltip', () => { expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); expect( originalMouseEnter ).toHaveBeenCalledTimes( 1 ); - // Popover does not yet exist after default delay, because custom delay is passed. + // Tooltip does not yet exist after default delay, because custom delay is passed. setTimeout( () => { expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); }, TOOLTIP_DELAY ); - // Popover appears after custom delay. + // Tooltip appears after custom delay. setTimeout( () => { expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); jest.runOnlyPendingTimers(); From 894e815b62d1e7ba88c177df01bd6a52ab1075b2 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 16:55:08 +0900 Subject: [PATCH 15/24] Add test to 'should render children' --- packages/components/src/tooltip/test/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 82ef24b783845..41912b5d48385 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -38,6 +38,7 @@ describe( 'Tooltip', () => { expect( screen.getByRole( 'button', { name: 'Hover Me!' } ) ).toBeInTheDocument(); + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); } ); it( 'should render children with additional tooltip when focused', () => { From 6dc8dcc95cc4314a89d6bb22c5156a2639778dc4 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:04:50 +0900 Subject: [PATCH 16/24] Merge two tests for focus --- packages/components/src/tooltip/test/index.js | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 41912b5d48385..52fdd4d3d2c9b 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -42,18 +42,29 @@ describe( 'Tooltip', () => { } ); it( 'should render children with additional tooltip when focused', () => { + const mockOnFocus = jest.fn(); + render( - + ); - const button = screen.getByRole( 'button' ); + const button = screen.getByRole( 'button', { name: 'Hover Me!' } ); + expect( button ).toBeInTheDocument(); + + // Before focus, the tooltip is not shown. + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); + button.focus(); - expect( - screen.getByRole( 'button', { name: 'Hover Me!' } ) - ).toBeInTheDocument(); + + // Tooltip is shown after focusing the anchor. expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); + expect( mockOnFocus ).toHaveBeenCalledWith( + expect.objectContaining( { + type: 'focus', + } ) + ); } ); it( 'should render children with additional tooltip when hovered', async () => { @@ -82,24 +93,6 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should show tooltip on focus', () => { - const originalFocus = jest.fn(); - render( - - - - ); - - const button = screen.getByRole( 'button' ); - button.focus(); - expect( originalFocus ).toHaveBeenCalledWith( - expect.objectContaining( { - type: 'focus', - } ) - ); - expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); - } ); - it( 'should not show tooltip on focus as result of mouse click', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, From 3cf023f148ec663d4d6a324a8b58b01616682af8 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:21:17 +0900 Subject: [PATCH 17/24] Refactor 'should render children with additional tooltip when hovered' test without and --- packages/components/src/tooltip/test/index.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 52fdd4d3d2c9b..8004875c0cb9a 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { render, screen } from '@testing-library/react'; +import { render, screen, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; /** @@ -71,7 +71,6 @@ describe( 'Tooltip', () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); - jest.useFakeTimers(); render( @@ -79,18 +78,18 @@ describe( 'Tooltip', () => { ); - const button = screen.getByRole( 'button' ); + const button = screen.getByRole( 'button', { name: 'Hover Me!' } ); + expect( button ).toBeInTheDocument(); + await user.hover( button ); - expect( - screen.getByRole( 'button', { name: 'Hover Me!' } ) - ).toBeInTheDocument(); + // Tooltip hasn't appeared yet + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); - setTimeout( () => { - expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - }, TOOLTIP_DELAY ); + act( () => jest.advanceTimersByTime( TOOLTIP_DELAY ) ); + + // Tooltip shows after the delay + expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); } ); it( 'should not show tooltip on focus as result of mouse click', async () => { From 2a150139850c594dac73b16b53035b30aba87fba Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:25:51 +0900 Subject: [PATCH 18/24] Rename from `handleClick` to `onClickMock` --- packages/components/src/tooltip/test/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 8004875c0cb9a..3b7a68a871faf 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -212,10 +212,10 @@ describe( 'Tooltip', () => { advanceTimers: jest.advanceTimersByTime, } ); - const handleClick = jest.fn(); + const onClickMock = jest.fn(); const { container } = render( - @@ -224,7 +224,7 @@ describe( 'Tooltip', () => { const eventCatcher = container.getElementsByClassName( 'event-catcher' )[ 0 ]; await user.click( eventCatcher ); - expect( handleClick ).not.toHaveBeenCalled(); + expect( onClickMock ).not.toHaveBeenCalled(); } ); it( 'should cancel pending setIsOver on mouseleave', async () => { From c8b1c0a5ff5cd743fc7b910f58795d22a25c14c7 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:28:41 +0900 Subject: [PATCH 19/24] Remove unnecessary test 'should show tooltip on delayed mouseenter' --- packages/components/src/tooltip/test/index.js | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 3b7a68a871faf..2c81af380cdb1 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -115,36 +115,6 @@ describe( 'Tooltip', () => { }, TOOLTIP_DELAY ); } ); - it( 'should show tooltip on delayed mouseenter', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); - - const originalMouseEnter = jest.fn(); - jest.useFakeTimers(); - render( - - - - ); - - const button = screen.getByRole( 'button' ); - await user.hover( button ); - expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); - expect( originalMouseEnter ).toHaveBeenCalledTimes( 1 ); - - setTimeout( () => { - expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - }, TOOLTIP_DELAY ); - } ); - it( 'should respect custom delay prop when showing tooltip', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, From dda605a1fd7fbfd6d391c874eca626cbec1321ec Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:32:44 +0900 Subject: [PATCH 20/24] Reactor: should not show tooltip on focus as result of mouse click --- packages/components/src/tooltip/test/index.js | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 2c81af380cdb1..7c49038e27598 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -96,23 +96,31 @@ describe( 'Tooltip', () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); - jest.useFakeTimers(); + const mockOnFocus = jest.fn(); render( - + ); - const button = screen.getByRole( 'button' ); + const button = screen.getByRole( 'button', { text: 'Hover Me!' } ); + expect( button ).toBeInTheDocument(); + await user.click( button ); - setTimeout( () => { - expect( - screen.queryByText( 'Help text' ) - ).not.toBeInTheDocument(); - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - }, TOOLTIP_DELAY ); + + // Tooltip hasn't appeared yet + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); + + act( () => jest.advanceTimersByTime( TOOLTIP_DELAY ) ); + + // Tooltip still hasn't appeared yet, even though the component was focused + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); + expect( mockOnFocus ).toHaveBeenCalledWith( + expect.objectContaining( { + type: 'focus', + } ) + ); } ); it( 'should respect custom delay prop when showing tooltip', async () => { From 4b143a0f960f233ce2ef7a24d30ac3662a875060 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:37:35 +0900 Subject: [PATCH 21/24] Refactor: should respect custom delay prop when showing tooltip --- packages/components/src/tooltip/test/index.js | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 7c49038e27598..1418466d89de5 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -128,36 +128,42 @@ describe( 'Tooltip', () => { advanceTimers: jest.advanceTimersByTime, } ); - const originalMouseEnter = jest.fn(); - jest.useFakeTimers(); + const TEST_DELAY = TOOLTIP_DELAY * 2; + const mockOnMouseEnter = jest.fn(); + const mockOnFocus = jest.fn(); + render( - + ); - const button = screen.getByRole( 'button' ); + const button = screen.getByRole( 'button', { name: 'Hover Me!' } ); + expect( button ).toBeInTheDocument(); + await user.hover( button ); + + // Tooltip hasn't appeared yet + expect( mockOnMouseEnter ).toHaveBeenCalledTimes( 1 ); + + // Advance by the usual TOOLTIP_DELAY + act( () => jest.advanceTimersByTime( TOOLTIP_DELAY ) ); + + // Tooltip hasn't appeared yet after the usual delay expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); - expect( originalMouseEnter ).toHaveBeenCalledTimes( 1 ); - // Tooltip does not yet exist after default delay, because custom delay is passed. - setTimeout( () => { - expect( - screen.queryByText( 'Help text' ) - ).not.toBeInTheDocument(); - }, TOOLTIP_DELAY ); - // Tooltip appears after custom delay. - setTimeout( () => { - expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - }, 2000 ); + // Advance time again, so that we reach the full TEST_DELAY time + act( () => jest.advanceTimersByTime( TEST_DELAY - TOOLTIP_DELAY ) ); + + // Tooltip shows after TEST_DELAY time + expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); + + expect( mockOnFocus ).not.toHaveBeenCalled(); } ); it( 'should show tooltip when an element is disabled', async () => { From 7f0367a5adfb903efd265e8f7de9c1cbcb389228 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:40:55 +0900 Subject: [PATCH 22/24] Refactor: should show tooltip when an element is disabled --- packages/components/src/tooltip/test/index.js | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 1418466d89de5..03aff2193d120 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -177,18 +177,30 @@ describe( 'Tooltip', () => { ); - const button = screen.getByRole( 'button' ); + const button = screen.getByRole( 'button', { name: 'Click me' } ); + expect( button ).toBeInTheDocument(); + expect( button ).toBeDisabled(); + + // Note: this is testing for implementation details, + // but couldn't find a better way. const buttonRect = button.getBoundingClientRect(); - const eventCatcher = - container.getElementsByClassName( 'event-catcher' )[ 0 ]; + const eventCatcher = container.querySelector( '.event-catcher' ); const eventCatcherRect = eventCatcher.getBoundingClientRect(); expect( buttonRect ).toEqual( eventCatcherRect ); await user.hover( eventCatcher ); - setTimeout( () => { - expect( screen.getByText( 'Help text' ) ).toBeInTheDocument(); - }, TOOLTIP_DELAY ); + // Tooltip hasn't appeared yet + expect( + screen.queryByText( 'Show helpful text here' ) + ).not.toBeInTheDocument(); + + act( () => jest.advanceTimersByTime( TOOLTIP_DELAY ) ); + + // Tooltip shows after the delay + expect( + screen.getByText( 'Show helpful text here' ) + ).toBeInTheDocument(); } ); it( 'should not emit events back to children when they are disabled', async () => { From 38b51af698e7e45f7e6b359111476bf6fa32f315 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Sat, 20 Aug 2022 17:43:39 +0900 Subject: [PATCH 23/24] Refactor: should not show tooltip if the mouse leaves the anchor before the tooltip has shown --- packages/components/src/tooltip/test/index.js | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/packages/components/src/tooltip/test/index.js b/packages/components/src/tooltip/test/index.js index 03aff2193d120..d126209cc8a18 100644 --- a/packages/components/src/tooltip/test/index.js +++ b/packages/components/src/tooltip/test/index.js @@ -223,30 +223,58 @@ describe( 'Tooltip', () => { expect( onClickMock ).not.toHaveBeenCalled(); } ); - it( 'should cancel pending setIsOver on mouseleave', async () => { + it( 'should not show tooltip if the mouse leaves the anchor before the tooltip has shown', async () => { const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime, } ); - const originalMouseEnter = jest.fn(); + const MOUSE_LEAVE_DELAY = TOOLTIP_DELAY - 200; + const onMouseEnterMock = jest.fn(); + const onMouseLeaveMock = jest.fn(); + render( - - - + <> + + + + + ); - const button = screen.getByRole( 'button' ); - await user.hover( button ); - setTimeout( () => { - expect( - screen.queryByText( 'Help text' ) - ).not.toBeInTheDocument(); - }, TOOLTIP_DELAY ); + const externalButton = screen.getByRole( 'button', { + name: 'Hover me instead!', + } ); + const tooltipButton = screen.getByRole( 'button', { + name: 'Hover Me!', + } ); + + await user.hover( tooltipButton ); + + // Tooltip hasn't appeared yet + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); + expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); + + // Advance time by MOUSE_LEAVE_DELAY time + act( () => jest.advanceTimersByTime( MOUSE_LEAVE_DELAY ) ); + + // Hover the other button, meaning that the mouse will leave the tooltip anchor + await user.hover( externalButton ); + + // Tooltip still hasn't appeared yet + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); + expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); + expect( onMouseLeaveMock ).toHaveBeenCalledTimes( 1 ); + + // Advance time again, so that we reach the full TOOLTIP_DELAY time + act( () => jest.advanceTimersByTime( TOOLTIP_DELAY ) ); + + // Tooltip won't show, since the mouse has left the anchor + expect( screen.queryByText( 'Help text' ) ).not.toBeInTheDocument(); } ); } ); } ); From e765736abb17dfddd57f5187ca5f1787aacf5277 Mon Sep 17 00:00:00 2001 From: Tetsuaki Hamano Date: Mon, 22 Aug 2022 23:03:59 +0900 Subject: [PATCH 24/24] Update changelog --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index d33e0c7bb25cc..b0b6757f51c83 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -27,6 +27,7 @@ ### Internal +- `Tooltip`: Refactor tests to `@testing-library/react` ([#43061](https://github.com/WordPress/gutenberg/pull/43061)). - Update `floating-ui` to the latest version ([#43206](https://github.com/WordPress/gutenberg/pull/43206)). - `DateTimePicker`, `TimePicker`, `DatePicker`: Switch from `moment` to `date-fns` ([#43005](https://github.com/WordPress/gutenberg/pull/43005)). - `DatePicker`: Switch from `react-dates` to `use-lilius` ([#43005](https://github.com/WordPress/gutenberg/pull/43005)).