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
SnackbarList, Snackbar: Add unit test #59157
Conversation
role={ ! explicitDismiss ? 'button' : '' } | ||
role={ ! explicitDismiss ? 'button' : undefined } | ||
onKeyPress={ ! explicitDismiss ? dismissMe : undefined } | ||
aria-label={ ! explicitDismiss ? __( 'Dismiss this notice' ) : '' } | ||
aria-label={ | ||
! explicitDismiss ? __( 'Dismiss this notice' ) : undefined | ||
} |
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.
Prevents attributes without values from being applied.
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 negation in all of these ternaries feels totally backwards to me, but hey ho... at least they're consistent!
Perhaps instead we could separate out the dismiss props?
// `explicitDismiss || { ... }` also works,
// as long as it's guaranteed to be a boolean!
const dismissProps = explicitDismiss ? {} : {
onClick: dismissMe,
onKeyPress: dismissMe,
role: 'button',
'aria-label': __( 'Dismiss this notice' ),
}
return (
<div { ...dismissProps } />
);
Anyway, scope creep 🚨
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.
Although this is a negative form, how about the following approach?
const dismissProps = {
onClick: dismissMe,
onKeyPress: dismissMe,
role: 'button',
'aria-label': __( 'Dismiss this notice' ),
};
return (
<div
// When there is no explicit close button to close the snackbar,
// give the snackbar itself a prop that can be dismissed.
{ ...( ! explicitDismiss && dismissProps ) }
>
);
@@ -70,7 +70,6 @@ Default.args = { | |||
}, | |||
], | |||
content: 'Post published.', | |||
isDismissible: true, |
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.
isDismissible
is not present in the Snackbar component's action
property.
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.
Can you clarify what you mean here? isDismissible
is a valid NoticeProp
, which SnackbarListProps.notices
ultimately derives from.
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.
Oh wait... this bit?
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 a little confusing, but the Snackbar
component inherits the type of the Notice
component. As mentioned in this comment, the current Snackbar
component inherits a type that contains unintended properties.
In fact, if you search the ./packages/components/src/snackbar
directory with isDismissible
, you shouldn't find any code containing isDismissible
.
} ); | ||
} ); | ||
|
||
describe( 'useSpokenMessage', () => { |
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.
This is the same as testing the Notice component. We are testing the useSpokenMessage
hook itself, and if it has been tested with the Notice
component, there might be no need to test it again here.
*/ | ||
import SnackbarList from '../list'; | ||
|
||
window.scrollTo = jest.fn(); |
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.
When the Snackbar
component is removed, the animation runs through motion.div
. If we don't mock window.scrollTo
, the following error seems to occur.
expect(jest.fn()).not.toHaveErrored(expected)
Expected mock function not to be called but it was called with:
[[Error: Not implemented: window.scrollTo]],[[Error: Not implemented: window.scrollTo]]
Flaky tests detected in 65f7b6b. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7953430355
|
@@ -28,8 +32,32 @@ type SnackbarOnlyProps = { | |||
listRef?: MutableRefObject< HTMLDivElement | null >; | |||
}; | |||
|
|||
export type SnackbarProps = Omit< NoticeProps, '__unstableHTML' > & | |||
SnackbarOnlyProps; | |||
export type SnackbarProps = Pick< |
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.
This was the part I had the most trouble with. This component uses the types of the Notice
component, and I discovered that the following types, which are not available in the Snackbar
component, also apply to the Snackbar
component.
isDismissible
status
actions.className
actions.noDefaultClasses
actions.variant
I used Pick
instead of Omit
so that when new props are added to the Notice
component in the future, they are not unintentionally exposed to the Snackbar
component as well.
At the same time, the code editor should also correctly display the description of the actions
prop.
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
@@ -138,9 +138,12 @@ function UnforwardedSnackbar( | |||
className={ classes } | |||
onClick={ ! explicitDismiss ? dismissMe : undefined } | |||
tabIndex={ 0 } | |||
role={ ! explicitDismiss ? 'button' : '' } | |||
role={ ! explicitDismiss ? 'button' : undefined } |
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.
May be a nitpick, and I might be missing something, but shouldn't an element without a role have a null
role instead of an undefined
one?
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.
Also, is "no-role" the best to do in this case? Is alert
or any other status
role a better fit perhaps? @andrewhayward what do you think?
Co-authored-by: Marin Atanasov <8436925+tyxla@users.noreply.github.com>
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.
Nothing further from my perspective. Nice work 🚀
Thanks for the review! This PR also includes a change to remove the |
Preparation to tackle #59139
What?
This PR adds unit tests for
SnackbarList
andSnackbar
components.Why?
While investigating #59139, I discovered that there are no unit tests for the Snackbar component.
Testing is necessary to ensure that the current implementation works as specified or to prevent future regressions.
How?
We tested as many cases as possible according to the actual implementation and README.
Testing Instructions
Run the following command:
npm run test:unit packages/components/src/snackbar/test/index.tsx
npm run test:unit packages/components/src/snackbar/test/list.tsx