Skip to content

Commit

Permalink
Refactoring BorderControl's unit tests (#54155)
Browse files Browse the repository at this point in the history
* Refactoring `BorderControl`'s unit tests

This patch migrates uses of `fireEvent` in `BorderControl` to `testing-library/user-event`, where possible; there is one remaining usage that isn't currently supported by `userEvent`.

* Updating failing tests – user error

Was running the wrong tests locally

* Replacing `user.clear` with a text selection range

Calling `user.clear` was necessary to prevent `user.type` from adding to an existing input value. However, by providing a selection range to `user.type` we can avoid that call entirely.

* Updating CHANGELOG.md
  • Loading branch information
andrewhayward committed Sep 5, 2023
1 parent 031d05d commit e2237b8
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 64 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@
### Internal

- `Composite`: Convert to TypeScript ([#54028](https://github.com/WordPress/gutenberg/pull/54028)).
- `BorderControl`: Refactor unit tests to use `userEvent` ([#54155](https://github.com/WordPress/gutenberg/pull/54155))

## 25.7.0 (2023-08-31)

Expand Down
138 changes: 74 additions & 64 deletions packages/components/src/border-control/test/index.js
@@ -1,13 +1,8 @@
/**
* External dependencies
*/
import {
act,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
Expand Down Expand Up @@ -47,9 +42,9 @@ function getWrappingPopoverElement( element ) {
return element.closest( '.components-popover' );
}

const openPopover = async () => {
const openPopover = async ( user ) => {
const toggleButton = screen.getByLabelText( toggleLabelRegex );
fireEvent.click( toggleButton );
await user.click( toggleButton );

// Wait for color picker popover to fully appear
const pickerButton = screen.getByRole( 'button', {
Expand All @@ -67,38 +62,21 @@ const getButton = ( name ) => {
return screen.getByRole( 'button', { name } );
};

const getColorOption = ( name ) => {
return screen.getByRole( 'option', { name } );
const getColorOption = ( color ) => {
return screen.getByRole( 'option', { name: `Color: ${ color }` } );
};

const queryButton = ( name ) => {
return screen.queryByRole( 'button', { name } );
};

const clickButton = ( name ) => {
fireEvent.click( getButton( name ) );
};

const selectColorOption = ( name ) => {
fireEvent.click( getColorOption( name ) );
};

const getSliderInput = () => {
return screen.getByRole( 'slider', { name: 'Border width' } );
};

const getWidthInput = () => {
return screen.getByRole( 'spinbutton', { name: 'Border width' } );
};
const setWidthInput = ( value ) => {
const widthInput = getWidthInput();
act( () => {
widthInput.focus();
} );
fireEvent.change( widthInput, { target: { value } } );
};

const clearWidthInput = () => setWidthInput( '' );

describe( 'BorderControl', () => {
describe( 'basic rendering', () => {
Expand Down Expand Up @@ -154,9 +132,10 @@ describe( 'BorderControl', () => {
} );

it( 'should render color and style popover', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
await openPopover( user );

const customColorPicker = getButton( /Custom color picker/ );
const colorSwatchButtons = screen.getAllByRole( 'option', {
Expand All @@ -178,9 +157,10 @@ describe( 'BorderControl', () => {
} );

it( 'should render color and style popover header', async () => {
const user = userEvent.setup();
const props = createProps( { showDropdownHeader: true } );
render( <BorderControl { ...props } /> );
await openPopover();
await openPopover( user );

const headerLabel = screen.getByText( 'Border color' );
const closeButton = getButton( 'Close border color' );
Expand All @@ -190,9 +170,10 @@ describe( 'BorderControl', () => {
} );

it( 'should not render style options when opted out of', async () => {
const user = userEvent.setup();
const props = createProps( { enableStyle: false } );
render( <BorderControl { ...props } /> );
await openPopover();
await openPopover( user );

const styleLabel = screen.queryByText( 'Style' );
const solidButton = queryButton( 'Solid' );
Expand Down Expand Up @@ -315,6 +296,10 @@ describe( 'BorderControl', () => {
const { rerender } = render( <BorderControl { ...props } /> );

const slider = getSliderInput();
// As per [1], it is not currently possible to reasonably
// replicate this interaction using `userEvent`, so leaving
// `fireEvent` in place to cover it.
// [1]: https://github.com/testing-library/user-event/issues/871
fireEvent.change( slider, { target: { value: '5' } } );

expect( props.onChange ).toHaveBeenNthCalledWith( 1, {
Expand All @@ -329,10 +314,11 @@ describe( 'BorderControl', () => {
} );

it( 'should update color selection', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Green' );
await openPopover( user );
await user.click( getColorOption( 'Green' ) );

expect( props.onChange ).toHaveBeenNthCalledWith( 1, {
...defaultBorder,
Expand All @@ -341,10 +327,11 @@ describe( 'BorderControl', () => {
} );

it( 'should clear color selection when toggling swatch off', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Blue' );
await openPopover( user );
await user.click( getColorOption( 'Blue' ) );

expect( props.onChange ).toHaveBeenNthCalledWith( 1, {
...defaultBorder,
Expand All @@ -353,10 +340,11 @@ describe( 'BorderControl', () => {
} );

it( 'should update style selection', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
clickButton( 'Dashed' );
await openPopover( user );
await user.click( getButton( 'Dashed' ) );

expect( props.onChange ).toHaveBeenNthCalledWith( 1, {
...defaultBorder,
Expand All @@ -365,19 +353,21 @@ describe( 'BorderControl', () => {
} );

it( 'should take no action when color and style popover is closed', async () => {
const user = userEvent.setup();
const props = createProps( { showDropdownHeader: true } );
render( <BorderControl { ...props } /> );
await openPopover();
clickButton( 'Close border color' );
await openPopover( user );
await user.click( getButton( 'Close border color' ) );

expect( props.onChange ).not.toHaveBeenCalled();
} );

it( 'should reset color and style only when popover reset button clicked', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
clickButton( 'Reset to default' );
await openPopover( user );
await user.click( getButton( 'Reset to default' ) );

expect( props.onChange ).toHaveBeenNthCalledWith( 1, {
color: undefined,
Expand All @@ -387,25 +377,27 @@ describe( 'BorderControl', () => {
} );

it( 'should sanitize border when width and color are undefined', async () => {
const user = userEvent.setup();
const props = createProps();
const { rerender } = render( <BorderControl { ...props } /> );
clearWidthInput();
await user.clear( getWidthInput() );
rerender( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Blue' );
await openPopover( user );
await user.click( getColorOption( 'Blue' ) );

expect( props.onChange ).toHaveBeenCalledWith( undefined );
} );

it( 'should not sanitize border when requested', async () => {
const user = userEvent.setup();
const props = createProps( {
shouldSanitizeBorder: false,
} );
const { rerender } = render( <BorderControl { ...props } /> );
clearWidthInput();
await user.clear( getWidthInput() );
rerender( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Blue' );
await openPopover( user );
await user.click( getColorOption( 'Blue' ) );

expect( props.onChange ).toHaveBeenNthCalledWith( 2, {
color: undefined,
Expand All @@ -415,12 +407,16 @@ describe( 'BorderControl', () => {
} );

it( 'should clear color and set style to `none` when setting zero width', async () => {
const user = userEvent.setup();
const props = createProps();
render( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Green' );
clickButton( 'Dotted' );
setWidthInput( '0' );
await openPopover( user );
await user.click( getColorOption( 'Green' ) );
await user.click( getButton( 'Dotted' ) );
await user.type( getWidthInput(), '0', {
initialSelectionStart: 0,
initialSelectionEnd: 1,
} );

expect( props.onChange ).toHaveBeenNthCalledWith( 3, {
color: undefined,
Expand All @@ -430,15 +426,23 @@ describe( 'BorderControl', () => {
} );

it( 'should reselect color and style selections when changing to non-zero width', async () => {
const user = userEvent.setup();
const props = createProps();
const { rerender } = render( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Green' );
await openPopover( user );
await user.click( getColorOption( 'Green' ) );
rerender( <BorderControl { ...props } /> );
clickButton( 'Dotted' );
await user.click( getButton( 'Dotted' ) );
rerender( <BorderControl { ...props } /> );
setWidthInput( '0' );
setWidthInput( '5' );
const widthInput = getWidthInput();
await user.type( widthInput, '0', {
initialSelectionStart: 0,
initialSelectionEnd: 1,
} );
await user.type( widthInput, '5', {
initialSelectionStart: 0,
initialSelectionEnd: 1,
} );

expect( props.onChange ).toHaveBeenNthCalledWith( 4, {
color: '#00a32a',
Expand All @@ -448,20 +452,23 @@ describe( 'BorderControl', () => {
} );

it( 'should set a non-zero width when applying color to zero width border', async () => {
const user = userEvent.setup();
const props = createProps( { value: undefined } );
const { rerender } = render( <BorderControl { ...props } /> );
await openPopover();
selectColorOption( 'Color: Yellow' );
await openPopover( user );
await user.click( getColorOption( 'Yellow' ) );

expect( props.onChange ).toHaveBeenCalledWith( {
color: '#bd8600',
style: undefined,
width: undefined,
} );

setWidthInput( '0' );
await user.type( getWidthInput(), '0' );

rerender( <BorderControl { ...props } /> );
selectColorOption( 'Color: Green' );
await openPopover( user );
await user.click( getColorOption( 'Green' ) );

expect( props.onChange ).toHaveBeenCalledWith( {
color: '#00a32a',
Expand All @@ -471,23 +478,26 @@ describe( 'BorderControl', () => {
} );

it( 'should set a non-zero width when applying style to zero width border', async () => {
const user = userEvent.setup();
const props = createProps( {
value: undefined,
shouldSanitizeBorder: false,
} );
const { rerender } = render( <BorderControl { ...props } /> );
await openPopover();
clickButton( 'Dashed' );
await openPopover( user );
await user.click( getButton( 'Dashed' ) );

expect( props.onChange ).toHaveBeenCalledWith( {
color: undefined,
style: 'dashed',
width: undefined,
} );

setWidthInput( '0' );
await user.type( getWidthInput(), '0' );

rerender( <BorderControl { ...props } /> );
clickButton( 'Dotted' );
await openPopover( user );
await user.click( getButton( 'Dotted' ) );

expect( props.onChange ).toHaveBeenCalledWith( {
color: undefined,
Expand Down

0 comments on commit e2237b8

Please sign in to comment.