-
Notifications
You must be signed in to change notification settings - Fork 7
Fix Menu activating the wrong option on open #1001
Conversation
🦋 Changeset detectedLatest commit: 69d08fe The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
728ab38
to
7e32113
Compare
51cf163
to
a625f52
Compare
padding-block-end: 0; | ||
padding-block-start: var(--glide-core-spacing-base-xxxs); | ||
padding-inline: var(--glide-core-spacing-base-xxxs); | ||
position: absolute; |
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.
A leftover from Menu's pre-Popover days. Unnecessary given it's now using the Popover API.
|
||
host.open = true; | ||
await aTimeout(0); // Wait for Floating UI | ||
await requestIdleCallback(); // Wait for Floating UI |
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.
Using aTimeout(0)
to wait for Floating UI has always bothered me because there's no guarantee that Floating UI takes no more than a tick—especially in CI, which runs weaker hardware.
Since I introduced sub-Menus into Menu, we've seen this inherent issue with aTimeout(0)
play out because sub-Menus create additional Floating UI work that, all together, sometimes take more than a tick to complete.
Waiting for the browser to become idle seems like the best way to wait for Floating UI in tests without components having to expose something (for example, a pseudo-private field that's a Promise) specifically for tests to wait on.
// `sendMouse()` is just a thin abstraction over Playwright's equivalent API. So | ||
// the ultimate cause is likely Playwright or Chromium's DevTools Protocol, which | ||
// Playwright relies on. It's that or I'm missing something obvious. Either way, | ||
// it was time to move on. |
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.
Narrator: "He was missing something obvious."
Or at least it appears that way. I've gotten nothing but green builds after switching to requestIdleCallback()
(below). I previously switched from await aTimeout(0)
to a programmatic click()
because I was reluctant to pass an even more arbitrary number to aTimeout()
.
But, it turns out, click()
didn't make these tests less flaky because of something to do with sendMouse()
—like I thought. Instead, it made these tests less flaky seemingly because it's synchronous and thus faster than sendMouse()
.
A programmatic click being faster, combined with the timeout on line 235, gave Floating UI just enough time to recalculate Menu's position—allowing the assertions below to succeed.
I wrote a short story below that'll give you more context.
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.
As a followup, I'll replace uses of aTimeout(0)
(at least ones used to wait for Floating UI) throughout the codebase with requestIdleCallback()
.
Tests that use requestIdleCallback()
will be slightly slower, because waiting for the browser to become idle takes longer than a single tick. But our tests should be far less flaky—if they're flaky at all. Or at least that's the idea. Time will tell.
06a6e2b
to
82687cd
Compare
82687cd
to
69d08fe
Compare
🚀 Description
📋 Checklist
🔬 Testing
As an aside, the reason the issue was reproducible in Storybook is because Storybook wraps our components in a
<div>
that's styled withtransform: scale(1)
—giving Menu a containing block that's something other than the document.You'll no longer be able to reproduce the issue on
main
if removetransform: scale(1)
from that<div>
.