From c3eea7baecf443ff69e93a282c0f9a6a48e449ea Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Sun, 29 May 2022 12:29:50 -0700 Subject: [PATCH 1/8] Use @testing-library/user-event in `InputControl` tests --- .../src/input-control/test/index.js | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index c7d18217eb479b..fe3668db2bd052 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -1,13 +1,19 @@ /** * External dependencies */ -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; /** * Internal dependencies */ import BaseInputControl from '../'; +const setupUser = () => + userEvent.setup( { + advanceTimers: jest.advanceTimersByTime, + } ); + const getInput = () => screen.getByTestId( 'input' ); describe( 'InputControl', () => { @@ -42,48 +48,52 @@ describe( 'InputControl', () => { } ); describe( 'Ensurance of focus for number inputs', () => { - it( 'should focus its input on mousedown events', () => { + it( 'should focus its input on mousedown events', async () => { + const user = setupUser(); const spy = jest.fn(); render( ); + const target = getInput(); - const input = getInput(); - fireEvent.mouseDown( input ); + // Hovers the input and presses (without releasing) primary button. + await user.pointer( [ + { target }, + { keys: '[MouseLeft]', target }, + ] ); expect( spy ).toHaveBeenCalledTimes( 1 ); } ); } ); describe( 'Value', () => { - it( 'should update value onChange', () => { + it( 'should update value onChange', async () => { + const user = setupUser(); const spy = jest.fn(); render( ); - const input = getInput(); - input.focus(); - fireEvent.change( input, { target: { value: 'There' } } ); - expect( input.value ).toBe( 'There' ); - expect( spy ).toHaveBeenCalledTimes( 1 ); + await user.type( input, ' there' ); + + expect( input ).toHaveValue( 'Hello there' ); + expect( spy ).toHaveBeenCalledTimes( 6 ); } ); - it( 'should work as a controlled component', () => { + it( 'should work as a controlled component', async () => { + const user = setupUser(); const spy = jest.fn(); const { rerender } = render( ); - const input = getInput(); - input.focus(); - fireEvent.change( input, { target: { value: 'two' } } ); + await user.type( input, '2' ); // Ensuring is controlled. - fireEvent.blur( input ); + await user.click( document.body ); - // Updating the value. + // Updating the value via props. rerender( ); - expect( input.value ).toBe( 'three' ); + expect( input ).toHaveValue( 'three' ); /* * onChange called only once. onChange is not called when a @@ -98,7 +108,6 @@ describe( 'InputControl', () => { const { rerender } = render( ); - const input = getInput(); // Assuming is controlled (not focused) @@ -106,12 +115,12 @@ describe( 'InputControl', () => { // Updating the value. rerender( ); - expect( input.value ).toBe( 'New' ); + expect( input ).toHaveValue( 'New' ); // Change it back to the original value. rerender( ); - expect( input.value ).toBe( 'Original' ); + expect( input ).toHaveValue( 'Original' ); expect( spy ).toHaveBeenCalledTimes( 0 ); } ); } ); From e118c8a46bcfff5398eebcb5a183263d83b932f8 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Sun, 29 May 2022 12:31:15 -0700 Subject: [PATCH 2/8] Add two new tests --- .../src/input-control/test/index.js | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index fe3668db2bd052..402fffc64b75c7 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -123,5 +123,53 @@ describe( 'InputControl', () => { expect( input ).toHaveValue( 'Original' ); expect( spy ).toHaveBeenCalledTimes( 0 ); } ); + + it( 'should not commit value until blurred when isPressEnterToChange is true', async () => { + const user = setupUser(); + const spy = jest.fn(); + render( + spy( v ) } + isPressEnterToChange + /> + ); + const input = getInput(); + + await user.type( input, 'that was then' ); + await user.click( document.body ); + + expect( spy ).toHaveBeenCalledTimes( 1 ); + expect( spy ).toHaveBeenCalledWith( 'that was then' ); + } ); + + it( 'should commit value when blurred if value is invalid', async () => { + const user = setupUser(); + const spyChange = jest.fn(); + render( + spyChange( v ) } + // If the value contains 'now' it is not valid. + pattern="(?!.*now)^.*$" + __unstableStateReducer={ ( state, action ) => { + let { value } = state; + if ( + action.type === 'COMMIT' && + action.payload.event.type === 'blur' + ) + value = value.replace( /\bnow\b/, 'meow' ); + + return { ...state, value }; + } } + /> + ); + const input = getInput(); + + await user.type( input, ' now' ); + await user.click( document.body ); + + expect( spyChange ).toHaveBeenLastCalledWith( 'this is meow' ); + } ); } ); } ); From 91d905d214bfc9d808553bc4b613664bddc04688 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Sun, 29 May 2022 14:03:03 -0700 Subject: [PATCH 3/8] Add changelog entry --- packages/components/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 4253e78f4f40f2..28212ff5cae664 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- `InputControl`: Add tests and update to use `@testing-library/user-event` ([#41421](https://github.com/WordPress/gutenberg/pull/41421)). + ## 19.13.0 (2022-06-15) ### Bug Fix From a298df3a40a5fa6d90c1adffae9164f55cb56204 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Thu, 2 Jun 2022 11:05:42 -0700 Subject: [PATCH 4/8] Address feedback --- packages/components/src/input-control/test/index.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index 402fffc64b75c7..3658deacb2850b 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -68,13 +68,16 @@ describe( 'InputControl', () => { it( 'should update value onChange', async () => { const user = setupUser(); const spy = jest.fn(); - render( ); + render( + spy( v ) } /> + ); const input = getInput(); await user.type( input, ' there' ); expect( input ).toHaveValue( 'Hello there' ); expect( spy ).toHaveBeenCalledTimes( 6 ); + expect( spy ).toHaveBeenLastCalledWith( 'Hello there' ); } ); it( 'should work as a controlled component', async () => { @@ -86,15 +89,13 @@ describe( 'InputControl', () => { const input = getInput(); await user.type( input, '2' ); - - // Ensuring is controlled. + // Blurs the input. await user.click( document.body ); // Updating the value via props. rerender( ); expect( input ).toHaveValue( 'three' ); - /* * onChange called only once. onChange is not called when a * parent component explicitly passed a (new value) change down to @@ -110,8 +111,6 @@ describe( 'InputControl', () => { ); const input = getInput(); - // Assuming is controlled (not focused) - // Updating the value. rerender( ); From acabb632416322b386082310c0e885c1a53c59fb Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Tue, 7 Jun 2022 18:50:52 -0700 Subject: [PATCH 5/8] Comment on document clicks for intent --- packages/components/src/input-control/test/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index 3658deacb2850b..04b3fe18352c78 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -89,7 +89,7 @@ describe( 'InputControl', () => { const input = getInput(); await user.type( input, '2' ); - // Blurs the input. + // Clicking document.body to trigger a blur event on the input. await user.click( document.body ); // Updating the value via props. @@ -136,6 +136,7 @@ describe( 'InputControl', () => { const input = getInput(); await user.type( input, 'that was then' ); + // Clicking document.body to trigger a blur event on the input. await user.click( document.body ); expect( spy ).toHaveBeenCalledTimes( 1 ); From 6af38a519947e6e2d451169f2504c51ce9c7731b Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Wed, 15 Jun 2022 10:15:06 -0700 Subject: [PATCH 6/8] Assert number of calls more explicitly Co-authored-by: Marco Ciampini --- packages/components/src/input-control/test/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index 04b3fe18352c78..be0383185ab89f 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -76,7 +76,7 @@ describe( 'InputControl', () => { await user.type( input, ' there' ); expect( input ).toHaveValue( 'Hello there' ); - expect( spy ).toHaveBeenCalledTimes( 6 ); + expect( spy ).toHaveBeenCalledTimes( ' there'.length ); expect( spy ).toHaveBeenLastCalledWith( 'Hello there' ); } ); From 1cb89787febdca232efe62b351ea4f38a3b0f58d Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Wed, 15 Jun 2022 10:33:04 -0700 Subject: [PATCH 7/8] Test as controlled component more explicitly --- .../src/input-control/test/index.js | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index be0383185ab89f..ec7f9cee89cac2 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -4,6 +4,11 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + /** * Internal dependencies */ @@ -83,17 +88,29 @@ describe( 'InputControl', () => { it( 'should work as a controlled component', async () => { const user = setupUser(); const spy = jest.fn(); - const { rerender } = render( - - ); + const Example = () => { + const [ state, setState ] = useState( 'one' ); + const onChange = ( value ) => { + setState( value ); + spy( value ); + }; + const onKeyDown = ( { key } ) => { + if ( key === 'Escape' ) setState( 'three' ); + }; + return ( + + ); + }; + render( ); const input = getInput(); await user.type( input, '2' ); - // Clicking document.body to trigger a blur event on the input. - await user.click( document.body ); - - // Updating the value via props. - rerender( ); + // Make a controlled update. + await user.keyboard( '{Escape}' ); expect( input ).toHaveValue( 'three' ); /* From f448bc69ffc8f9ad0abe362aa0245dc0bcacb432 Mon Sep 17 00:00:00 2001 From: Mitchell Austin Date: Wed, 15 Jun 2022 10:35:40 -0700 Subject: [PATCH 8/8] Comment for intent of document body click --- packages/components/src/input-control/test/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/input-control/test/index.js b/packages/components/src/input-control/test/index.js index ec7f9cee89cac2..ebdf97ee8d7a38 100644 --- a/packages/components/src/input-control/test/index.js +++ b/packages/components/src/input-control/test/index.js @@ -184,6 +184,7 @@ describe( 'InputControl', () => { const input = getInput(); await user.type( input, ' now' ); + // Clicking document.body to trigger a blur event on the input. await user.click( document.body ); expect( spyChange ).toHaveBeenLastCalledWith( 'this is meow' );