-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
FontSizePicker: Rewrite unit tests to use userEvent and be more comprehensive #45298
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for improving the unit tests. Good coverage 👍
I left some questions about testing the header hint and labels.
it( 'should fallback to font size `slug` for header hint label if `name` is undefined', () => { | ||
const fontSizes = [ | ||
{ | ||
slug: 'gigantosaurus', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have something against gigantosauruses? 🦖
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I'll put her back.
value={ value } | ||
/> | ||
); | ||
// TODO: There's no accessible way to select the label. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did I miss that! I'll query for the existence of an element with that label 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also going to point out that in case you need to do exact test matching across multiple DOM elements, you can pass a custom matcher to screen.getByText
:
function textContentMatcher( textMatch: string | RegExp ) {
const hasText =
typeof textMatch === 'string'
? ( node: Element | null ) => node?.textContent === textMatch
: ( node: Element | null ) =>
textMatch.test( node?.textContent ?? '' );
const matcherFn: MatcherFunction = ( _content, node ) => {
if ( ! hasText( node ) ) {
return false;
}
const childrenDontHaveText = Array.from( node?.children || [] ).every(
( child ) => ! hasText( child )
);
return childrenDontHaveText;
};
return matcherFn;
}
// later, in a test:
const label = screen.getByText(
textContentMatcher( expectedHint )
);
const label = document.querySelector( | ||
'.components-base-control__label' | ||
); | ||
expect( label ).toHaveTextContent( expectedHint ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expectedHint
in this test case doesn't look right to me.
Could it be that the test is passing because toHaveTextContent does partial matches?
If we're only interested in testing whether the accessible label and text hint are set correctly, then another option might be to just pass a single fontSize for the label you want to test:
test.each( [
{
value: undefined,
expectedHint: 'Size Default',
fontSizePresets: [ fontSizes[ 0 ] ],
},
{
value: '8px',
expectedHint: 'Size Tiny(px)',
fontSizePresets: [ fontSizes[ 0 ] ],
},
{
value: '3px',
expectedHint: 'Size (Custom)',
fontSizePresets: [ fontSizes[ 0 ] ],
},
] )(
'displays $expectedHint as header hint when value is $value',
( { value, expectedHint, fontSizePresets } ) => {
render(
<FontSizePicker
__nextHasNoMarginBottom
fontSizes={ fontSizePresets }
value={ value }
/>
);
const label = screen.getByLabelText( expectedHint );
expect( label ).toBeInTheDocument();
expect( label ).toHaveTextContent(
// Removes whitespaces to match text interspersed in HTML elements.
expectedHint.replace( /\s*/g, '' )
);
}
);
This avoids have to fire an event to click on preset buttons and what not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By fixing your other comment I think I inadvertently fixed this, good catch 😀
Thanks @ramonjd! Updated this per your feedback and added a changelog entry. |
About to post my review as, sorry for the delay! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @noisysocks for working on this!!
Apart from the inline comments, it looks like we're not adding tests for:
- "complex" CSS values (e.g
clamp(1.75rem, 3vw, 2.25rem)
) - font sizes with different units (i.e some in
px
, some inrem
, ...)
Those are probably some of the harder to test edge cases, and therefore it would be nice to have unit tests for those too!
I want to make @ciampo happy
I'm flattered 😊
value={ value } | ||
/> | ||
); | ||
// TODO: There's no accessible way to select the label. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also going to point out that in case you need to do exact test matching across multiple DOM elements, you can pass a custom matcher to screen.getByText
:
function textContentMatcher( textMatch: string | RegExp ) {
const hasText =
typeof textMatch === 'string'
? ( node: Element | null ) => node?.textContent === textMatch
: ( node: Element | null ) =>
textMatch.test( node?.textContent ?? '' );
const matcherFn: MatcherFunction = ( _content, node ) => {
if ( ! hasText( node ) ) {
return false;
}
const childrenDontHaveText = Array.from( node?.children || [] ).every(
( child ) => ! hasText( child )
);
return childrenDontHaveText;
};
return matcherFn;
}
// later, in a test:
const label = screen.getByText(
textContentMatcher( expectedHint )
);
); | ||
expect( screen.getByLabelText( 'Custom' ) ).toBeInTheDocument(); | ||
// TODO: onChange() shouldn't be called. | ||
//expect( onChange ).not.toHaveBeenCalled(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good find! Adding a comment here so that we don't miss this as a follow-up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's one of the things we fixed in #44891 :)
Addressed some of the feedback. I'll add more tests for non-px values tomorrow. |
Okey dokey, I've added tests for non- |
Thank YOU for always taking the time to make significant improvements to the components you work on! |
What?
Rewrites the
FontSizePicker
unit tests to useuserEvent
where possible and be more comprehensive.Why?
I want to make @ciampo happy 🙂 see #44891 (review).
How?
I looked at the
FontSizePicker
component storybook, listed all of the functionality that I could think of, and then wrote new tests from scratch that covered everything that I listed.Testing Instructions
npm run test
, obviously, but the more important thing is to review the code and check that I haven't missed anything.Screenshots or screencast