Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components: Refactor Tooltip tests to @testing-library/react #43061

Merged
merged 25 commits into from
Aug 22, 2022
Merged
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8603386
Migrate frim enzyme to testing-library
t-hamano Aug 8, 2022
5764d4a
update text matcher
t-hamano Aug 8, 2022
5901f73
Fix typo
t-hamano Aug 8, 2022
02520e8
Update matcher
t-hamano Aug 9, 2022
19d029c
Refactor fireEvent to userEvent
t-hamano Aug 12, 2022
28b1abe
Brush up test (tooltip won't be rendered)
t-hamano Aug 12, 2022
10274ad
Refactor setTimeout to findBy in one test
t-hamano Aug 12, 2022
d6f98a7
Don't use getElementsByClassName
t-hamano Aug 12, 2022
cdafb54
Don't use nodeName, childNodes
t-hamano Aug 12, 2022
81b473b
Remove unused event handler
t-hamano Aug 15, 2022
3126a88
Remove tootip position props
t-hamano Aug 15, 2022
4e9b4cf
Add test: should render children with additional popover when hovered
t-hamano Aug 15, 2022
d5e17de
Simplify mouse click test
t-hamano Aug 15, 2022
7aa6669
Standardize test cases name
t-hamano Aug 20, 2022
894e815
Add test to 'should render children'
t-hamano Aug 20, 2022
6dc8dcc
Merge two tests for focus
t-hamano Aug 20, 2022
3cf023f
Refactor 'should render children with additional tooltip when hovered…
t-hamano Aug 20, 2022
2a15013
Rename from `handleClick` to `onClickMock`
t-hamano Aug 20, 2022
c8b1c0a
Remove unnecessary test 'should show tooltip on delayed mouseenter'
t-hamano Aug 20, 2022
dda605a
Reactor: should not show tooltip on focus as result of mouse click
t-hamano Aug 20, 2022
4b143a0
Refactor: should respect custom delay prop when showing tooltip
t-hamano Aug 20, 2022
7f0367a
Refactor: should show tooltip when an element is disabled
t-hamano Aug 20, 2022
38b51af
Refactor: should not show tooltip if the mouse leaves the anchor befo…
t-hamano Aug 20, 2022
f5604cc
Merge branch 'trunk' into refactor/tooltip-test-to-testing-library
t-hamano Aug 20, 2022
e765736
Update changelog
t-hamano Aug 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 74 additions & 87 deletions packages/components/src/tooltip/test/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { shallow, mount } from 'enzyme';
import { fireEvent, render, screen } from '@testing-library/react';
ciampo marked this conversation as resolved.
Show resolved Hide resolved

/**
* Internal dependencies
Expand All @@ -11,60 +11,55 @@ 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', () => {
ciampo marked this conversation as resolved.
Show resolved Hide resolved
// Mount: Enzyme shallow does not support wrapping multiple nodes.
const wrapper = mount(
const { container } = render(
<Tooltip>
<div />
<div />
</Tooltip>
);

expect( wrapper.children() ).toHaveLength( 2 );
expect( container.children ).toHaveLength( 2 );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
} );

it( 'should render children', () => {
const wrapper = shallow(
render(
<Tooltip position="bottom right" text="Help text">
<button>Hover Me!</button>
</Tooltip>
);

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 ).toHaveTextContent( 'Hover Me!' );
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
} );

it( 'should render children with additional popover when over', () => {
const wrapper = shallow(
const { container } = render(
<Tooltip position="bottom right" text="Help text">
<button>Hover Me!</button>
</Tooltip>
);

const event = { type: 'focus', currentTarget: {} };
wrapper.simulate( 'focus', event );
const button = screen.getByRole( 'button' );
button.focus();
expect( button.nodeName ).toBe( 'BUTTON' );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
expect( button.childNodes ).toHaveLength( 2 );
expect( button.childNodes[ 0 ] ).toHaveTextContent( 'Hover Me!' );
ciampo marked this conversation as resolved.
Show resolved Hide resolved

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' );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
expect( popover.children().first().text() ).toBe( 'Help text' );
const popover =
container.getElementsByClassName( 'components-popover' );
expect( popover ).toHaveLength( 1 );
expect( popover[ 0 ].firstChild ).toHaveTextContent( 'Help text' );
} );
t-hamano marked this conversation as resolved.
Show resolved Hide resolved

it( 'should show popover on focus', () => {
ciampo marked this conversation as resolved.
Show resolved Hide resolved
const originalFocus = jest.fn();
const event = { type: 'focus', currentTarget: {} };
const wrapper = shallow(
const { container } = render(
<Tooltip text="Help text">
<button
onMouseEnter={ originalFocus }
ciampo marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -75,18 +70,23 @@ describe( 'Tooltip', () => {
</Tooltip>
);

const button = wrapper.find( 'button' );
button.simulate( 'focus', event );
const button = screen.getByRole( 'button' );
button.focus();

const popover = wrapper.find( 'ForwardRef(Popover)' );
expect( originalFocus ).toHaveBeenCalledWith( event );
const popover =
ciampo marked this conversation as resolved.
Show resolved Hide resolved
container.getElementsByClassName( 'components-popover' );
expect( originalFocus ).toHaveBeenCalledWith(
expect.objectContaining( {
type: 'focus',
} )
);
expect( popover ).toHaveLength( 1 );
} );

it( 'should show not popover on focus as result of mousedown', async () => {
it( 'should not show popover on focus as result of mousedown', async () => {
ciampo marked this conversation as resolved.
Show resolved Hide resolved
const originalOnMouseDown = jest.fn();
const originalOnMouseUp = jest.fn();
const wrapper = mount(
const { container } = render(
<Tooltip text="Help text">
<button
onMouseDown={ originalOnMouseDown }
Expand All @@ -97,37 +97,31 @@ describe( 'Tooltip', () => {
</Tooltip>
);

const button = wrapper.find( 'button' );

let event;

event = { type: 'mousedown' };
button.simulate( event.type, event );
const button = screen.getByRole( 'button' );
fireEvent.mouseDown( button );
expect( originalOnMouseDown ).toHaveBeenCalledWith(
expect.objectContaining( {
type: event.type,
type: 'mousedown',
} )
);

event = { type: 'focus', currentTarget: {} };
button.simulate( event.type, event );

const popover = wrapper.find( 'Popover' );
button.focus();
const popover =
container.getElementsByClassName( 'components-popover' );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
expect( popover ).toHaveLength( 0 );

event = new window.MouseEvent( 'mouseup' );
await act( async () => document.dispatchEvent( event ) );
fireEvent.mouseUp( button );
expect( originalOnMouseUp ).toHaveBeenCalledWith(
expect.objectContaining( {
type: event.type,
type: 'mouseup',
} )
);
} );

it( 'should show popover on delayed mouseenter', () => {
ciampo marked this conversation as resolved.
Show resolved Hide resolved
const originalMouseEnter = jest.fn();
jest.useFakeTimers();
const wrapper = mount(
const { container } = render(
<Tooltip text="Help text">
<button
onMouseEnter={ originalMouseEnter }
Expand All @@ -138,16 +132,17 @@ describe( 'Tooltip', () => {
</Tooltip>
);

const button = wrapper.find( 'button' );
button.simulate( 'mouseenter', { type: 'mouseenter' } );

const popoverBeforeTimeout = wrapper.find( 'Popover' );
const button = screen.getByRole( 'button' );
fireEvent.mouseOver( button );
const popoverBeforeTimeout =
container.getElementsByClassName( 'components-popover' );
expect( popoverBeforeTimeout ).toHaveLength( 0 );
expect( originalMouseEnter ).toHaveBeenCalledTimes( 1 );

// Force delayedSetIsOver to be called.
setTimeout( () => {
const popoverAfterTimeout = wrapper.find( 'Popover' );
const popoverAfterTimeout =
container.getElementsByClassName( 'components-popover' );
expect( popoverAfterTimeout ).toHaveLength( 1 );

jest.runOnlyPendingTimers();
Expand All @@ -158,7 +153,7 @@ describe( 'Tooltip', () => {
it( 'should respect custom delay prop when showing popover', () => {
const originalMouseEnter = jest.fn();
jest.useFakeTimers();
const wrapper = mount(
const { container } = render(
<Tooltip text="Help text" delay={ 2000 }>
<button
onMouseEnter={ originalMouseEnter }
Expand All @@ -169,79 +164,71 @@ describe( 'Tooltip', () => {
</Tooltip>
);

const button = wrapper.find( 'button' );
button.simulate( 'mouseenter', { type: 'mouseenter' } );

const popoverBeforeTimeout = wrapper.find( 'Popover' );
const button = screen.getByRole( 'button' );
fireEvent.mouseOver( button );
const popoverBeforeTimeout =
container.getElementsByClassName( 'components-popover' );
expect( popoverBeforeTimeout ).toHaveLength( 0 );
expect( originalMouseEnter ).toHaveBeenCalledTimes( 1 );

// Popover does not yet exist after default delay, because custom delay is passed.
setTimeout( () => {
const popoverBetweenTimeout = wrapper.find( 'Popover' );
const popoverBetweenTimeout =
container.getElementsByClassName( 'components-popover' );
expect( popoverBetweenTimeout ).toHaveLength( 0 );
}, TOOLTIP_DELAY );

// Popover appears after custom delay.
setTimeout( () => {
const popoverAfterTimeout = wrapper.find( 'Popover' );
const popoverAfterTimeout =
container.getElementsByClassName( 'components-popover' );
expect( popoverAfterTimeout ).toHaveLength( 1 );

jest.runOnlyPendingTimers();
jest.useRealTimers();
}, 2000 );
} );

it( 'should show tooltip when an element is disabled', () => {
ciampo marked this conversation as resolved.
Show resolved Hide resolved
const wrapper = mount(
const { container } = render(
<Tooltip text="Show helpful text here">
<button disabled>Click me</button>
</Tooltip>
);
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();
ciampo marked this conversation as resolved.
Show resolved Hide resolved

const wrapper = mount(
const { container } = render(
<Tooltip text="Show helpful text here">
<button disabled onClick={ handleClick }>
Click me
</button>
</Tooltip>
);

const eventCatcher = wrapper.find( '.event-catcher' );
eventCatcher.simulate( 'click', {
type: 'click',
currentTarget: {},
} );

expect( handleClick ).toHaveBeenCalledTimes( 0 );
const eventCatcher =
container.getElementsByClassName( 'event-catcher' )[ 0 ];
fireEvent.click( eventCatcher );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
expect( handleClick ).not.toHaveBeenCalled();
} );

it( 'should cancel pending setIsOver on mouseleave', () => {
// Mount: Issues with using `setState` asynchronously with shallow-
// rendered components: https://github.com/airbnb/enzyme/issues/450
const originalMouseEnter = jest.fn();
const wrapper = mount(
const { container } = render(
<Tooltip text="Help text">
<button
onMouseEnter={ originalMouseEnter }
Expand All @@ -252,11 +239,11 @@ describe( 'Tooltip', () => {
</Tooltip>
);

const button = wrapper.find( 'button' );
button.simulate( 'mouseenter' );

const button = screen.getByRole( 'button' );
fireEvent.mouseOver( button );
setTimeout( () => {
const popover = wrapper.find( 'Popover' );
const popover =
container.getElementsByClassName( 'components-popover' );
expect( popover ).toHaveLength( 0 );
}, TOOLTIP_DELAY );
} );
Expand Down