Skip to content

Commit

Permalink
Normalize v1 and v2 legacy tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ciampo committed Jun 20, 2024
1 parent 1dd5c70 commit c7530a3
Show file tree
Hide file tree
Showing 2 changed files with 281 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { useState } from '@wordpress/element';
*/
import UncontrolledCustomSelectControl from '..';

const className = 'amber-skies';
const style = {
const customClassName = 'amber-skies';
const customStyles = {
backgroundColor: 'rgb(127, 255, 212)',
rotate: '13deg',
};
Expand All @@ -30,7 +30,7 @@ const legacyProps = {
{
key: 'flower2',
name: 'crimson clover',
className,
className: customClassName,
},
{
key: 'flower3',
Expand All @@ -39,18 +39,18 @@ const legacyProps = {
{
key: 'color1',
name: 'amber',
className,
className: customClassName,
},
{
key: 'color2',
name: 'aquamarine',
style,
style: customStyles,
},
{
key: 'aquarela-key',
name: 'aquarela',
className,
style,
key: 'color3',
name: 'tomato (with custom props)',
className: customClassName,
style: customStyles,
// try passing a valid HTML attribute
'aria-label': 'test label',
// try adding a custom prop
Expand All @@ -61,18 +61,21 @@ const legacyProps = {

const ControlledCustomSelectControl = ( {
options,
onChange,
onChange: onChangeProp,
...restProps
}: React.ComponentProps< typeof UncontrolledCustomSelectControl > ) => {
const [ value, setValue ] = useState( options[ 0 ] );

const onChange: typeof onChangeProp = ( changeObject ) => {
onChangeProp?.( changeObject );
setValue( changeObject.selectedItem );
};

return (
<UncontrolledCustomSelectControl
{ ...restProps }
options={ options }
onChange={ ( args: any ) => {
onChange?.( args );
setValue( args.selectedItem );
} }
onChange={ onChange }
value={ options.find(
( option: any ) => option.key === value.key
) }
Expand Down Expand Up @@ -101,6 +104,8 @@ describe.each( [
} )
);

// TODO: also check `value` instead of just content,
// here and everywhere else in the file
expect( currentSelectedItem ).toHaveTextContent( 'crimson clover' );

await click( currentSelectedItem );
Expand Down Expand Up @@ -159,7 +164,7 @@ describe.each( [
// assert against filtered array
itemsWithClass.map( ( { name } ) =>
expect( screen.getByRole( 'option', { name } ) ).toHaveClass(
className
customClassName
)
);

Expand All @@ -171,15 +176,12 @@ describe.each( [
// assert against filtered array
itemsWithoutClass.map( ( { name } ) =>
expect( screen.getByRole( 'option', { name } ) ).not.toHaveClass(
className
customClassName
)
);
} );

it( 'Should apply styles only to options that have styles defined', async () => {
const customStyles =
'background-color: rgb(127, 255, 212); rotate: 13deg;';

render( <Component { ...legacyProps } /> );

await click(
Expand Down Expand Up @@ -255,7 +257,7 @@ describe.each( [
screen.getByRole( 'combobox', {
expanded: false,
} )
).toHaveTextContent( /hint/i )
).toHaveTextContent( 'Hint' )
);
} );

Expand Down Expand Up @@ -292,6 +294,8 @@ describe.each( [
} )
);

// NOTE: legacy CustomSelectControl doesn't fire onChange
// at this point in time.
expect( mockOnChange ).toHaveBeenNthCalledWith(
1,
expect.objectContaining( {
Expand Down Expand Up @@ -322,9 +326,7 @@ describe.each( [
} );

it( 'Should return selectedItem object when specified onChange', async () => {
const mockOnChange = jest.fn(
( { selectedItem } ) => selectedItem.key
);
const mockOnChange = jest.fn();

render( <Component { ...legacyProps } onChange={ mockOnChange } /> );

Expand All @@ -336,13 +338,103 @@ describe.each( [
} )
).toHaveFocus();

// NOTE: legacy CustomSelectControl doesn't fire onChange
// at this point in time.
expect( mockOnChange ).toHaveBeenNthCalledWith(
1,
expect.objectContaining( {
selectedItem: expect.objectContaining( {
key: 'flower1',
name: 'violets',
} ),
} )
);

await type( 'p' );
await press.Enter();

expect( mockOnChange ).toHaveReturnedWith( 'flower1' );
expect( mockOnChange ).toHaveBeenNthCalledWith(
2,
expect.objectContaining( {
selectedItem: expect.objectContaining( {
key: 'flower3',
name: 'poppy',
} ),
} )
);
} );

it( 'Should accept and pass arbitrary properties to the selectedItem object in the onChange callback, but without applying them to the DOM elements apart from style and classname', async () => {
const onChangeMock = jest.fn();

render( <Component { ...legacyProps } onChange={ onChangeMock } /> );

const currentSelectedItem = screen.getByRole( 'combobox', {
expanded: false,
} );

await click( currentSelectedItem );

const optionWithCustomAttributes = screen.getByRole( 'option', {
name: 'tomato (with custom props)',
} );

// Assert that the option element does not have the custom attributes
expect( optionWithCustomAttributes ).not.toHaveAttribute(
'customPropFoo'
);
expect( optionWithCustomAttributes ).not.toHaveAttribute(
'aria-label'
);

await click( optionWithCustomAttributes );

// NOTE: legacy CustomSelectControl doesn't fire onChange
// on first render, and so at this point in time `onChangeMock`
// would be called only once.
expect( onChangeMock ).toHaveBeenCalledTimes( 2 );
expect( onChangeMock ).toHaveBeenCalledWith(
expect.objectContaining( {
selectedItem: expect.objectContaining( {
key: 'color3',
name: 'tomato (with custom props)',
className: customClassName,
style: customStyles,
'aria-label': 'test label',
customPropFoo: 'foo',
} ),
} )
);
} );

describe( 'Keyboard behavior and accessibility', () => {
// skip reason: legacy v2 doesn't currently implement this behavior
it.skip( 'Captures the keypress event and does not let it propagate', async () => {
const onKeyDown = jest.fn();

render(
<div
// This role="none" is required to prevent an eslint warning about accessibility.
role="none"
onKeyDown={ onKeyDown }
>
<Component { ...legacyProps } />
</div>
);
const currentSelectedItem = screen.getByRole( 'combobox', {
expanded: false,
} );
await click( currentSelectedItem );

const customSelect = screen.getByRole( 'listbox', {
name: 'label!',
} );
expect( customSelect ).toHaveFocus();
await press.Enter();

expect( onKeyDown ).toHaveBeenCalledTimes( 0 );
} );

it( 'Should be able to change selection using keyboard', async () => {
render( <Component { ...legacyProps } /> );

Expand Down Expand Up @@ -467,43 +559,34 @@ describe.each( [
} )
).toBeVisible();
} );
} );

// V1 styles items via a `style` or `className` metadata property in the option item object. Some consumers still expect it, e.g:
// - https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/font-appearance-control/index.js#L216
// Besides that, the `option` prop is documented as havin the type:
// - `Array<{ key: String, name: String, style: ?{}, className: ?String, ...rest }>`
// Notice the `...test` there. We should keep supporting the arbitrary props like this.
it( 'Should return style and custom metadata as part of the selected option from onChange', async () => {
const mockOnChange = jest.fn();

render( <Component { ...legacyProps } onChange={ mockOnChange } /> );
it( 'Should call custom event handlers', async () => {
const onFocusMock = jest.fn();
const onBlurMock = jest.fn();

render(
<>
<Component
{ ...legacyProps }
onFocus={ onFocusMock }
onBlur={ onBlurMock }
/>
<button>Focus stop</button>
</>
);

await click(
screen.getByRole( 'combobox', {
const currentSelectedItem = screen.getByRole( 'combobox', {
expanded: false,
} )
);

const optionElement = screen.getByRole( 'option', {
name: 'aquarela',
} );
} );

// Assert that the option element does not have the custom attributes
expect( optionElement ).not.toHaveAttribute( 'customPropFoo' );
expect( optionElement ).not.toHaveAttribute( 'aria-label' );
await press.Tab();

await click( optionElement );
expect( currentSelectedItem ).toHaveFocus();
expect( onFocusMock ).toHaveBeenCalledTimes( 1 );

expect( mockOnChange ).toHaveBeenCalledWith(
expect.objectContaining( {
selectedItem: expect.objectContaining( {
className,
style,
customPropFoo: 'foo',
'aria-label': 'test label',
} ),
} )
);
await press.Tab();
expect( currentSelectedItem ).not.toHaveFocus();
expect( onBlurMock ).toHaveBeenCalledTimes( 1 );
} );
} );
} );
Loading

0 comments on commit c7530a3

Please sign in to comment.