Skip to content

🤖 tests: close the MCP server popover with a retried Escape in story plays - #7656

Merged
ThomasK33 merged 1 commit into
mainfrom
tests/7650-popover-escape-wait
Oct 27, 2026
Merged

ThomasK33 merged 1 commit into
mainfrom
tests/7650-popover-escape-wait

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

The ServerDetails and PluginServerDetails story plays in App.mcpToolIdentity.stories.tsx now close the "About ..." server popover with a new helper, closeWithEscape(layer). The helper presses Escape again while the popover is still open, so an Escape that Radix ignores no longer fails the play. Story-only change, no product change.

Fixes #7650

Background

#7651 added waitForModalLayer for modal dialogs and left these two plays out (#7650). The "About ..." element is a non-modal Radix Popover (MCPServerIdentityBadge.tsx:86).

Radix ignores Escape until a new layer's second re-render (@radix-ui/react-dismissable-layer/dist/index.mjs):

  1. :40 computes the layer's index at render. It is -1 until the node is in context.layers.
  2. :68-78 adds the node in an effect and dispatches dismissableLayer.update.
  3. :94 re-renders on that update. Only then is :60 isHighestLayer true, so Escape dismisses.

A modal layer shows step 3 as inline pointer-events: auto (:104), which waitForModalLayer waits on. A non-modal layer gets no inline style, and nothing else in the DOM changes on that re-render. Focus inside the content is not a safe signal either: the popover's FocusScope auto-focus (react-popover/dist/index.mjs:227) runs in the same effect flush, before the re-render.

Implementation

closeWithEscape(layer) in src/browser/stories/storyPlayHelpers.ts runs a waitFor (5 s). In each try it presses Escape only while the layer has data-state="open" (react-popover/dist/index.mjs:242), then fails until the layer is gone. An accepted Escape sets data-state="closed" in the same discrete event, so the helper presses no Escape after the popover took one. It replaces keyboard("{Escape}") plus waitFor(not.toBeInTheDocument()) at the three Escape presses in the two plays.

Trade-off: the plays now prove "Escape closes the popover", not "the first Escape closes it". A bug that makes the first Escape do nothing would pass. Without a DOM signal for the Radix re-render (:40, :60, :94 above), I found no deterministic alternative short of a product change. Tracked in #7657.

Validation

Same method as #7651: in the built Storybook asset I changed Radix's update listener from const T=()=>f({}) to const T=()=>setTimeout(()=>f({}),1000), served storybook-static, and ran bun x test-storybook --url ... --testTimeout 60000 --maxWorkers=4 src/browser/stories/App.mcpToolIdentity.stories.tsx. I removed the patched build after the runs.

Run Build Result
Delayed update origin/main c7221ac 2 failed of 11 (ServerDetails, PluginServerDetails: expect(element).not.toBeInTheDocument())
Delayed update, 3 runs this branch 11 passed of 11, each run
No delay this branch 11 passed of 11

Local gates: make static-check, make lint-eslint, make dry-check.

Risks

Low. Only two story plays and one new story helper change.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $449.92

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T00:49:21.919236Z 62ca697 PR opened
🔒 Security Review ✅ Completed 2026-10-27T00:50:00.973507Z 62ca697 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

22 agent steps · 7 replayed from cache · 15 model calls · 46.5k tokens (24% cached)
Spend: $0.09 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 1 step · 1 call 5.4s
🟢 a chat survives a restart of the server 1 step · 1 call 5.4s
🟢 compaction.e2e.ts · 1 passed 1 step · 1 call 4.5s
🟢 /compact replaces the old chat with a summary 1 step · 1 call 4.5s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 9.6s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 9.6s
🟢 settingsRoundTrip.e2e.ts · 1 passed 2 steps · 1 call 8.8s
🟢 a chat survives trips through Settings 2 steps · 1 call 8.8s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.3s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.3s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.8s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.8s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 6.8s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 6.8s
🟢 todoNudge.e2e.ts · 1 passed 1 step · 1 call 4.5s
🟢 the agent finishes open TODO items after the turn-end nudge 1 step · 1 call 4.5s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 29.8s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 4.2s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 4.6s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 4.3s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 10.3s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 3.1s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 3.3s

e2e 0.20.0 · 1m 20s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.0k tokens (22% cached)
Spend: $0.02 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 5.5s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 5.5s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 5.6s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 5.6s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 5.3s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 5.3s

e2e 0.20.0 · 18.4s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 5.3s · 2 targets (web, phone) · run artifacts

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 02320c4 Oct 27, 2026
33 of 34 checks passed
@ThomasK33
ThomasK33 deleted the tests/7650-popover-escape-wait branch October 27, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🤖 tests: MCP server popover stories press Escape before the Radix layer is on top

1 participant