Skip to content

Commit

Permalink
Use @testing-library/user-event in BoxControl tests (#41422)
Browse files Browse the repository at this point in the history
* Use @testing-library/user-event in `BoxControl` tests

* Add changelog entry
  • Loading branch information
stokesman authored and youknowriad committed Jun 3, 2022
1 parent 62caba6 commit db720d7
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 109 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
229 changes: 120 additions & 109 deletions packages/components/src/box-control/test/index.js
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -23,42 +33,41 @@ describe( 'BoxControl', () => {
expect( input ).toBeTruthy();
} );

it( 'should update values when interacting with input', () => {
const { container } = render( <BoxControl /> );
const input = container.querySelector( 'input' );
const unitSelect = container.querySelector( 'select' );
it( 'should update values when interacting with input', async () => {
const user = setupUser();
render( <BoxControl /> );
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( <BoxControl /> );
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( <BoxControl /> );
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();

Expand All @@ -69,26 +78,25 @@ describe( 'BoxControl', () => {
/>
);
};
const { container, getByText } = render( <Example /> );
const input = container.querySelector( 'input' );
const unitSelect = container.querySelector( 'select' );
const reset = getByText( /Reset/ );
const user = setupUser();
render( <Example /> );
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();

Expand All @@ -106,70 +114,78 @@ describe( 'BoxControl', () => {
/>
);
};
const { container, getByText } = render( <Example /> );
const input = container.querySelector( 'input' );
const unitSelect = container.querySelector( 'select' );
const reset = getByText( /Reset/ );
const user = setupUser();
render( <Example /> );
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( <BoxControl /> );
it( 'should persist cleared value when focus changes', async () => {
const user = setupUser();
const spyChange = jest.fn();
render( <BoxControl onChange={ ( v ) => 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(
<BoxControl
values={ state }
onChange={ ( next ) => 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',
Expand All @@ -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(
<BoxControl
values={ state }
onChange={ ( next ) => 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',
Expand All @@ -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( <BoxControl /> );
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( <BoxControl /> );
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' );
Expand All @@ -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( <BoxControl onChange={ setState } /> );
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',
Expand All @@ -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( <BoxControl onChange={ setState } /> );
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,
Expand Down

0 comments on commit db720d7

Please sign in to comment.