diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 28a64f2fb37c1..852c1ef5b7e66 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -24,6 +24,7 @@
- `TimePicker`: Update unit tests to use `@testing-library/user-event` ([#41270](https://github.com/WordPress/gutenberg/pull/41270)).
- `DateTimePicker`: Update `moment` to 2.26.0 and update `react-date` typings ([#41266](https://github.com/WordPress/gutenberg/pull/41266)).
- `TextareaControl`: Convert to TypeScript ([#41215](https://github.com/WordPress/gutenberg/pull/41215)).
+- `BoxControl`: Update unit tests to use `@testing-library/user-event` ([#41422](https://github.com/WordPress/gutenberg/pull/41422)).
### Experimental
diff --git a/packages/components/src/box-control/test/index.js b/packages/components/src/box-control/test/index.js
index 4515c4885c90f..c98dd3b48d43a 100644
--- a/packages/components/src/box-control/test/index.js
+++ b/packages/components/src/box-control/test/index.js
@@ -1,19 +1,29 @@
/**
* External dependencies
*/
-import { render, fireEvent, screen } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
-import { ENTER } from '@wordpress/keycodes';
/**
* Internal dependencies
*/
import BoxControl from '../';
+const setupUser = () =>
+ userEvent.setup( {
+ advanceTimers: jest.advanceTimersByTime,
+ } );
+
+const getInput = () =>
+ screen.getByLabelText( 'Box Control', { selector: 'input' } );
+const getSelect = () => screen.getByLabelText( 'Select unit' );
+const getReset = () => screen.getByText( /Reset/ );
+
describe( 'BoxControl', () => {
describe( 'Basic rendering', () => {
it( 'should render', () => {
@@ -23,42 +33,41 @@ describe( 'BoxControl', () => {
expect( input ).toBeTruthy();
} );
- it( 'should update values when interacting with input', () => {
- const { container } = render( );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
+ it( 'should update values when interacting with input', async () => {
+ const user = setupUser();
+ render( );
+ const input = getInput();
+ const select = getSelect();
- input.focus();
- fireEvent.change( input, { target: { value: '100%' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100%' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( '%' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( '%' );
} );
} );
describe( 'Reset', () => {
- it( 'should reset values when clicking Reset', () => {
- const { container, getByText } = render( );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
- const reset = getByText( /Reset/ );
+ it( 'should reset values when clicking Reset', async () => {
+ const user = setupUser();
+ render( );
+ const input = getInput();
+ const select = getSelect();
+ const reset = getReset();
- input.focus();
- fireEvent.change( input, { target: { value: '100px' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100px' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( 'px' );
- reset.focus();
- fireEvent.click( reset );
+ await user.click( reset );
- expect( input.value ).toBe( '' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '' );
+ expect( select ).toHaveValue( 'px' );
} );
- it( 'should reset values when clicking Reset, if controlled', () => {
+ it( 'should reset values when clicking Reset, if controlled', async () => {
const Example = () => {
const [ state, setState ] = useState();
@@ -69,26 +78,25 @@ describe( 'BoxControl', () => {
/>
);
};
- const { container, getByText } = render( );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
- const reset = getByText( /Reset/ );
+ const user = setupUser();
+ render( );
+ const input = getInput();
+ const select = getSelect();
+ const reset = getReset();
- input.focus();
- fireEvent.change( input, { target: { value: '100px' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100px' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( 'px' );
- reset.focus();
- fireEvent.click( reset );
+ await user.click( reset );
- expect( input.value ).toBe( '' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '' );
+ expect( select ).toHaveValue( 'px' );
} );
- it( 'should reset values when clicking Reset, if controlled <-> uncontrolled state changes', () => {
+ it( 'should reset values when clicking Reset, if controlled <-> uncontrolled state changes', async () => {
const Example = () => {
const [ state, setState ] = useState();
@@ -106,70 +114,78 @@ describe( 'BoxControl', () => {
/>
);
};
- const { container, getByText } = render( );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
- const reset = getByText( /Reset/ );
+ const user = setupUser();
+ render( );
+ const input = getInput();
+ const select = getSelect();
+ const reset = getReset();
- input.focus();
- fireEvent.change( input, { target: { value: '100px' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100px' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( 'px' );
- reset.focus();
- fireEvent.click( reset );
+ await user.click( reset );
- expect( input.value ).toBe( '' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '' );
+ expect( select ).toHaveValue( 'px' );
} );
- it( 'should persist cleared value when focus changes', () => {
- render( );
+ it( 'should persist cleared value when focus changes', async () => {
+ const user = setupUser();
+ const spyChange = jest.fn();
+ render( spyChange( v ) } /> );
const input = screen.getByLabelText( 'Box Control', {
selector: 'input',
} );
const unitSelect = screen.getByLabelText( 'Select unit' );
- input.focus();
- fireEvent.change( input, { target: { value: '100%' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100%' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( '%' );
+ expect( input ).toHaveValue( '100' );
+ expect( unitSelect ).toHaveValue( '%' );
- fireEvent.change( input, { target: { value: '' } } );
- fireEvent.blur( input );
+ await user.clear( input );
+ expect( input ).toHaveValue( '' );
+ // Clicking document.body to trigger a blur event on the input.
+ await user.click( document.body );
- expect( input.value ).toBe( '' );
+ expect( input ).toHaveValue( '' );
+ expect( spyChange ).toHaveBeenLastCalledWith( {
+ top: undefined,
+ right: undefined,
+ bottom: undefined,
+ left: undefined,
+ } );
} );
} );
describe( 'Unlinked Sides', () => {
- it( 'should update a single side value when unlinked', () => {
+ it( 'should update a single side value when unlinked', async () => {
let state = {};
const setState = ( newState ) => ( state = newState );
- const { container, getByLabelText } = render(
+ const { getAllByLabelText, getByLabelText } = render(
setState( next ) }
/>
);
-
+ const user = setupUser();
const unlink = getByLabelText( /Unlink Sides/ );
- fireEvent.click( unlink );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
+ await user.click( unlink );
+
+ const input = getByLabelText( /Top/ );
+ const select = getAllByLabelText( /Select unit/ )[ 0 ];
- input.focus();
- fireEvent.change( input, { target: { value: '100px' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100px' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( 'px' );
expect( state ).toEqual( {
top: '100px',
@@ -179,30 +195,30 @@ describe( 'BoxControl', () => {
} );
} );
- it( 'should update a whole axis when value is changed when unlinked', () => {
+ it( 'should update a whole axis when value is changed when unlinked', async () => {
let state = {};
const setState = ( newState ) => ( state = newState );
- const { container, getByLabelText } = render(
+ const { getAllByLabelText, getByLabelText } = render(
setState( next ) }
splitOnAxis={ true }
/>
);
-
+ const user = setupUser();
const unlink = getByLabelText( /Unlink Sides/ );
- fireEvent.click( unlink );
- const input = container.querySelector( 'input' );
- const unitSelect = container.querySelector( 'select' );
+ await user.click( unlink );
+
+ const input = getByLabelText( /Vertical/ );
+ const select = getAllByLabelText( /Select unit/ )[ 0 ];
- input.focus();
- fireEvent.change( input, { target: { value: '100px' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '100px' );
+ await user.keyboard( '{Enter}' );
- expect( input.value ).toBe( '100' );
- expect( unitSelect.value ).toBe( 'px' );
+ expect( input ).toHaveValue( '100' );
+ expect( select ).toHaveValue( 'px' );
expect( state ).toEqual( {
top: '100px',
@@ -214,36 +230,34 @@ describe( 'BoxControl', () => {
} );
describe( 'Unit selections', () => {
- it( 'should update unlinked controls unit selection based on all input control', () => {
+ it( 'should update unlinked controls unit selection based on all input control', async () => {
// Render control.
render( );
+ const user = setupUser();
// Make unit selection on all input control.
- const allUnitSelect = screen.getByLabelText( 'Select unit' );
- allUnitSelect.focus();
- fireEvent.change( allUnitSelect, { target: { value: 'em' } } );
+ const allUnitSelect = getSelect();
+ await user.selectOptions( allUnitSelect, [ 'em' ] );
// Unlink the controls.
- const unlink = screen.getByLabelText( /Unlink Sides/ );
- fireEvent.click( unlink );
+ await user.click( screen.getByLabelText( /Unlink Sides/ ) );
// Confirm that each individual control has the selected unit
const unlinkedSelects = screen.getAllByDisplayValue( 'em' );
expect( unlinkedSelects.length ).toEqual( 4 );
} );
- it( 'should use individual side attribute unit when available', () => {
+ it( 'should use individual side attribute unit when available', async () => {
// Render control.
const { rerender } = render( );
+ const user = setupUser();
// Make unit selection on all input control.
- const allUnitSelect = screen.getByLabelText( 'Select unit' );
- allUnitSelect.focus();
- fireEvent.change( allUnitSelect, { target: { value: 'vw' } } );
+ const allUnitSelect = getSelect();
+ await user.selectOptions( allUnitSelect, [ 'vw' ] );
// Unlink the controls.
- const unlink = screen.getByLabelText( /Unlink Sides/ );
- fireEvent.click( unlink );
+ await user.click( screen.getByLabelText( /Unlink Sides/ ) );
// Confirm that each individual control has the selected unit
const unlinkedSelects = screen.getAllByDisplayValue( 'vw' );
@@ -261,18 +275,15 @@ describe( 'BoxControl', () => {
} );
describe( 'onChange updates', () => {
- it( 'should call onChange when values contain more than just CSS units', () => {
+ it( 'should call onChange when values contain more than just CSS units', async () => {
const setState = jest.fn();
render( );
+ const user = setupUser();
+ const input = getInput();
- const input = screen.getByLabelText( 'Box Control', {
- selector: 'input',
- } );
-
- input.focus();
- fireEvent.change( input, { target: { value: '7.5rem' } } );
- fireEvent.keyDown( input, { keyCode: ENTER } );
+ await user.type( input, '7.5rem' );
+ await user.keyboard( '{Enter}' );
expect( setState ).toHaveBeenCalledWith( {
top: '7.5rem',
@@ -282,14 +293,14 @@ describe( 'BoxControl', () => {
} );
} );
- it( 'should not pass invalid CSS unit only values to onChange', () => {
+ it( 'should not pass invalid CSS unit only values to onChange', async () => {
const setState = jest.fn();
render( );
+ const user = setupUser();
- const allUnitSelect = screen.getByLabelText( 'Select unit' );
- allUnitSelect.focus();
- fireEvent.change( allUnitSelect, { target: { value: 'rem' } } );
+ const allUnitSelect = getSelect();
+ await user.selectOptions( allUnitSelect, 'rem' );
expect( setState ).toHaveBeenCalledWith( {
top: undefined,