diff --git a/packages/components/src/color-picker/test/index.tsx b/packages/components/src/color-picker/test/index.tsx index f531455f734e7e..8d584d626487a4 100644 --- a/packages/components/src/color-picker/test/index.tsx +++ b/packages/components/src/color-picker/test/index.tsx @@ -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 ), @@ -73,99 +38,134 @@ 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( ); - 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( + + ); + + 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( - - ); + 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', 'Red', '#7dffff' ], + [ 'green', 'Green', '#ff7dff' ], + [ 'blue', 'Blue', '#ffff7d' ], + ] )( 'RGB inputs', ( colorInput, inputLabel, 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( + + ); - 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.getByRole( 'spinbutton', { + name: inputLabel, + } ); + 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( - - ); + expect( onChange ).toHaveBeenCalledTimes( 4 ); + expect( onChange ).toHaveBeenLastCalledWith( expected ); + } ); + } ); - const saturation = getSaturation( container ); + describe.each( [ + [ 'hue', 'Hue', '#aad52a' ], + [ 'saturation', 'Saturation', '#20dfdf' ], + [ 'lightness', 'Lightness', '#95eaea' ], + ] )( 'HSL inputs', ( colorInput, inputLabel, 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( + + ); - 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.getByRole( 'spinbutton', { + name: inputLabel, + } ); + 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 ); + } ); } ); } );