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: Refactor Icon tests to @testing-library/react #44051

Merged
merged 6 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

### Internal

- `Icon`: Refactor tests to `@testing-library/react` ([#44051](https://github.com/WordPress/gutenberg/pull/44051)).
- Fix TypeScript types for `isValueDefined()` and `isValueEmpty()` utility functions ([#43983](https://github.com/WordPress/gutenberg/pull/43983)).
- `RadioControl`: Clean up styles to use less custom CSS ([#43868](https://github.com/WordPress/gutenberg/pull/43868)).
- Remove unused `normalizeArrowKey` utility function ([#43640](https://github.com/WordPress/gutenberg/pull/43640/)).
Expand All @@ -38,7 +39,7 @@
- Refactor `FocalPointPicker` to function component ([#39168](https://github.com/WordPress/gutenberg/pull/39168)).
- `Guide`: use `code` instead of `keyCode` for keyboard events ([#43604](https://github.com/WordPress/gutenberg/pull/43604/)).
- `ToggleControl`: Convert to TypeScript and streamline CSS ([#43717](https://github.com/WordPress/gutenberg/pull/43717)).
- `FocalPointPicker`: Convert to TypeScript ([#43872](https://github.com/WordPress/gutenberg/pull/43872)).
- `FocalPointPicker`: Convert to TypeScript ([#43872](https://github.com/WordPress/gutenberg/pull/43872)).
- `Navigation`: use `code` instead of `keyCode` for keyboard events ([#43644](https://github.com/WordPress/gutenberg/pull/43644/)).
- `ComboboxControl`: Add unit tests ([#42403](https://github.com/WordPress/gutenberg/pull/42403)).
- `NavigableContainer`: use `code` instead of `keyCode` for keyboard events, rewrite tests using RTL and `user-event` ([#43606](https://github.com/WordPress/gutenberg/pull/43606/)).
Expand Down
113 changes: 31 additions & 82 deletions packages/components/src/icon/test/index.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,67 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { render, screen } from '@testing-library/react';

/**
* Internal dependencies
*/
import Dashicon from '../../dashicon';
import Icon from '../';
import { Path, SVG } from '../../';

describe( 'Icon', () => {
const testId = 'icon';
const className = 'example-class';
const svg = (
<SVG>
<Path d="M5 4v3h5.5v12h3V7H19V4z" />
</SVG>
);
const style = { fill: 'red' };

it( 'renders nothing when icon omitted', () => {
const wrapper = shallow( <Icon /> );
render( <Icon data-testid={ testId } /> );

expect( wrapper.type() ).toBeNull();
expect( screen.queryByTestId( testId ) ).not.toBeInTheDocument();
} );

it( 'renders a dashicon by slug', () => {
const wrapper = shallow( <Icon icon="format-image" /> );
render( <Icon data-testid={ testId } icon="format-image" /> );

expect( wrapper.find( 'Dashicon' ).prop( 'icon' ) ).toBe(
'format-image'
expect( screen.getByTestId( testId ) ).toHaveClass(
'dashicons-format-image'
);
} );

it( 'renders a function', () => {
const wrapper = shallow( <Icon icon={ () => <span /> } /> );
render( <Icon icon={ () => <span data-testid={ testId } /> } /> );

expect( wrapper.name() ).toBe( 'span' );
expect( screen.getByTestId( testId ) ).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to use .toBeVisible() which is a bit more specific than .toBeInTheDocument()?

} );

it( 'renders an element', () => {
const wrapper = shallow( <Icon icon={ <span /> } /> );
render( <Icon icon={ <span data-testid={ testId } /> } /> );

expect( wrapper.name() ).toBe( 'span' );
expect( screen.getByTestId( testId ) ).toBeInTheDocument();
} );

it( 'renders an svg element', () => {
const wrapper = shallow( <Icon icon={ svg } /> );
render( <Icon data-testid={ testId } icon={ svg } /> );

expect( wrapper.name() ).toBe( 'SVG' );
expect( screen.getByTestId( testId ) ).toBeInTheDocument();
} );

it( 'renders an svg element with a default width and height of 24', () => {
const wrapper = shallow( <Icon icon={ svg } /> );
render( <Icon data-testid={ testId } icon={ svg } /> );
const icon = screen.queryByTestId( testId );
Copy link
Member

@tyxla tyxla Sep 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to use get* instead of query* here, see this for the rationale.

Suggested change
const icon = screen.queryByTestId( testId );
const icon = screen.getByTestId( testId );


expect( wrapper.prop( 'width' ) ).toBe( 24 );
expect( wrapper.prop( 'height' ) ).toBe( 24 );
expect( icon ).toHaveAttribute( 'width', '24' );
expect( icon ).toHaveAttribute( 'height', '24' );
} );

it( 'renders an svg element and override its width and height', () => {
const wrapper = shallow(
render(
<Icon
data-testid={ testId }
icon={
<SVG width={ 64 } height={ 64 }>
<Path d="M5 4v3h5.5v12h3V7H19V4z" />
Expand All @@ -74,73 +70,26 @@ describe( 'Icon', () => {
size={ 32 }
/>
);
const icon = screen.queryByTestId( testId );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const icon = screen.queryByTestId( testId );
const icon = screen.getByTestId( testId );


expect( wrapper.prop( 'width' ) ).toBe( 32 );
expect( wrapper.prop( 'height' ) ).toBe( 32 );
expect( icon ).toHaveAttribute( 'width', '32' );
expect( icon ).toHaveAttribute( 'height', '32' );
} );

it( 'renders an svg element and does not override width and height if already specified', () => {
const wrapper = shallow( <Icon icon={ svg } size={ 32 } /> );
render( <Icon data-testid={ testId } icon={ svg } size={ 32 } /> );
const icon = screen.queryByTestId( testId );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const icon = screen.queryByTestId( testId );
const icon = screen.getByTestId( testId );


expect( wrapper.prop( 'width' ) ).toBe( 32 );
expect( wrapper.prop( 'height' ) ).toBe( 32 );
expect( icon ).toHaveAttribute( 'width', '32' );
expect( icon ).toHaveAttribute( 'height', '32' );
} );

it( 'renders a component', () => {
class MyComponent extends Component {
render() {
return <span />;
}
}
const wrapper = shallow( <Icon icon={ MyComponent } /> );

expect( wrapper.name() ).toBe( 'MyComponent' );
} );

describe( 'props passing', () => {
class MyComponent extends Component {
render() {
return <span className={ this.props.className } />;
}
}

describe.each( [
[ 'dashicon', { icon: 'format-image' } ],
[ 'dashicon element', { icon: <Dashicon icon="format-image" /> } ],
[ 'element', { icon: <span /> } ],
[ 'svg element', { icon: svg } ],
[ 'component', { icon: MyComponent } ],
] )( '%s', ( label, props ) => {
it( 'should pass through size', () => {
if ( label === 'svg element' ) {
// Custom logic for SVG elements tested separately.
//
// See: `renders an svg element and passes the size as its width and height`
return;
}

if ( [ 'dashicon', 'dashicon element' ].includes( label ) ) {
// `size` prop isn't passed through, since dashicon doesn't accept it.
return;
}

const wrapper = shallow( <Icon { ...props } size={ 32 } /> );

expect( wrapper.prop( 'size' ) ).toBe( 32 );
} );

it( 'should pass through all other props', () => {
const wrapper = shallow(
<Icon
{ ...props }
style={ style }
className={ className }
/>
);
const MyComponent = () => (
<span data-testid={ testId } className={ className } />
);
render( <Icon icon={ MyComponent } /> );

expect( wrapper.prop( 'style' ) ).toBe( style );
expect( wrapper.prop( 'className' ) ).toBe( className );
} );
} );
expect( screen.getByTestId( testId ) ).toHaveClass( className );
} );
} );