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: update ColorPicker unit tests #49698

Merged
merged 10 commits into from
Apr 18, 2023
196 changes: 97 additions & 99 deletions packages/components/src/color-picker/test/index.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,14 @@
/**
* External dependencies
*/
import { render, fireEvent, waitFor } from '@testing-library/react';
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
*/
import { ColorPicker } from '..';

/**
* Ordinarily we'd try to select the component by role but the slider role appears
* on several elements and we'd end up encoding assumptions about order when
* trying to select the appropriate element. We might as well just use the class name
* on the container which will be more durable if, for example, the order changes.
*/
function getSaturation( container: HTMLElement ) {
return container.querySelector(
'.react-colorful__saturation .react-colorful__interactive'
);
}

type PageXPageY = { pageX: number; pageY: number };

// Fix to pass `pageX` and `pageY`
// See https://github.com/testing-library/react-testing-library/issues/268
class FakeMouseEvent extends MouseEvent {
constructor( type: MouseEvent[ 'type' ], values?: PageXPageY ) {
super( type, { buttons: 1, bubbles: true, ...values } );

Object.assign( this, {
pageX: values?.pageX ?? 0,
pageY: values?.pageY ?? 0,
} );
}
}

function moveReactColorfulSlider(
sliderElement: Element,
from: PageXPageY,
to: PageXPageY
) {
fireEvent( sliderElement, new FakeMouseEvent( 'mousedown', from ) );
fireEvent( sliderElement, new FakeMouseEvent( 'mousemove', to ) );
}

const hslaMatcher = expect.objectContaining( {
h: expect.any( Number ),
s: expect.any( Number ),
Expand Down Expand Up @@ -73,99 +38,132 @@ const legacyColorMatcher = {
describe( 'ColorPicker', () => {
describe( 'legacy props', () => {
it( 'should fire onChangeComplete with the legacy color format', async () => {
const user = userEvent.setup();
const onChangeComplete = jest.fn();
const color = '#fff';
const color = '#000';

const { container } = render(
render(
<ColorPicker
onChangeComplete={ onChangeComplete }
color={ color }
enableAlpha={ false }
/>
);

const saturation = getSaturation( container );

if ( saturation === null ) {
throw new Error( 'The saturation slider could not be found' );
}
const formatSelector = screen.getByRole( 'combobox' );
expect( formatSelector ).toBeVisible();

expect( saturation ).toBeInTheDocument();
await user.selectOptions( formatSelector, 'hex' );

moveReactColorfulSlider(
saturation,
{ pageX: 0, pageY: 0 },
{ pageX: 10, pageY: 10 }
);
const hexInput = screen.getByRole( 'textbox' );
expect( hexInput ).toBeVisible();

await waitFor( () =>
expect( onChangeComplete ).toHaveBeenCalled()
);
await user.clear( hexInput );
await user.type( hexInput, '1ab' );

expect( onChangeComplete ).toHaveBeenCalledWith(
expect( onChangeComplete ).toHaveBeenCalledTimes( 3 );
expect( onChangeComplete ).toHaveBeenLastCalledWith(
legacyColorMatcher
);
} );
} );
describe( 'Hex input', () => {
it( 'should fire onChange with the correct value from the hex input', async () => {
const user = userEvent.setup();
const onChange = jest.fn();
const color = '#000';

render(
<ColorPicker
onChange={ onChange }
color={ color }
enableAlpha={ false }
/>
);

const formatSelector = screen.getByRole( 'combobox' );
expect( formatSelector ).toBeVisible();

await user.selectOptions( formatSelector, 'hex' );

it( 'should fire onChange with the string value', async () => {
const onChange = jest.fn();
const color = 'rgba(1, 1, 1, 0.5)';
const hexInput = screen.getByRole( 'textbox' );
expect( hexInput ).toBeVisible();

const { container } = render(
<ColorPicker onChange={ onChange } color={ color } enableAlpha />
);
await user.clear( hexInput );
await user.type( hexInput, '1ab' );

const saturation = getSaturation( container );
expect( onChange ).toHaveBeenCalledTimes( 3 );
expect( onChange ).toHaveBeenLastCalledWith( '#11aabb' );
} );
} );

if ( saturation === null ) {
throw new Error( 'The saturation slider could not be found' );
}
describe.each( [
[ 'red', 0, '#7dffff' ],
[ 'green', 1, '#ff7dff' ],
[ 'blue', 2, '#ffff7d' ],
] )( 'RGB inputs', ( colorInput, inputIndex, expected ) => {
it( `should fire onChange with the correct value when the ${ colorInput } value is updated`, async () => {
const user = userEvent.setup();
const onChange = jest.fn();
const color = '#fff';

expect( saturation ).toBeInTheDocument();
render(
<ColorPicker
onChange={ onChange }
color={ color }
enableAlpha={ false }
/>
);

moveReactColorfulSlider(
saturation,
{ pageX: 0, pageY: 0 },
{ pageX: 10, pageY: 10 }
);
const formatSelector = screen.getByRole( 'combobox' );
expect( formatSelector ).toBeVisible();

await waitFor( () => expect( onChange ).toHaveBeenCalled() );
await user.selectOptions( formatSelector, 'rgb' );

expect( onChange ).toHaveBeenCalledWith(
expect.stringMatching( /^#([a-fA-F0-9]{8})$/ )
);
} );
const inputElement =
screen.getAllByRole( 'spinbutton' )[ inputIndex ];
chad1008 marked this conversation as resolved.
Show resolved Hide resolved
expect( inputElement ).toBeVisible();

it( 'should fire onChange with the HSL value', async () => {
const onChange = jest.fn();
const color = 'hsla(125, 20%, 50%, 0.5)';
await user.clear( inputElement );
await user.type( inputElement, '125' );

const { container } = render(
<ColorPicker
onChange={ onChange }
color={ color }
enableAlpha={ false }
/>
);
expect( onChange ).toHaveBeenCalledTimes( 4 );
expect( onChange ).toHaveBeenLastCalledWith( expected );
} );
} );

const saturation = getSaturation( container );
describe.each( [
[ 'hue', 0, '#aad52a' ],
[ 'saturation', 1, '#20dfdf' ],
[ 'lightness', 2, '#95eaea' ],
] )( 'HSL inputs', ( colorInput, inputIndex, expected ) => {
it( `should fire onChange with the correct value when the ${ colorInput } value is updated`, async () => {
const user = userEvent.setup();
const onChange = jest.fn();
const color = '#2ad5d5';

render(
<ColorPicker
onChange={ onChange }
color={ color }
enableAlpha={ false }
/>
);

if ( saturation === null ) {
throw new Error( 'The saturation slider could not be found' );
}
const formatSelector = screen.getByRole( 'combobox' );
expect( formatSelector ).toBeVisible();

expect( saturation ).toBeInTheDocument();
await user.selectOptions( formatSelector, 'hsl' );

moveReactColorfulSlider(
saturation,
{ pageX: 0, pageY: 0 },
{ pageX: 10, pageY: 10 }
);
const inputElement =
screen.getAllByRole( 'spinbutton' )[ inputIndex ];
expect( inputElement ).toBeVisible();

await waitFor( () => expect( onChange ).toHaveBeenCalled() );
await user.clear( inputElement );
await user.type( inputElement, '75' );

expect( onChange ).toHaveBeenCalledWith(
expect.stringMatching( /^#([a-fA-F0-9]{6})$/ )
);
expect( onChange ).toHaveBeenCalledTimes( 3 );
expect( onChange ).toHaveBeenLastCalledWith( expected );
} );
} );
} );