test(desktop): stop the picker spec racing two upstream guards - #4225
test(desktop): stop the picker spec racing two upstream guards#4225orangeCatDeveloper wants to merge 2 commits into
Conversation
Reopening the picker right after choosing an item raced DropdownMenu's 50ms light-dismiss guard, which every hide arms, so the click was dropped and the spec failed on whichever machine ran the assertions between them fast enough. Generated-by: Claude Code
ChatComposerInput absorbs one echo of its own onChange, so two keystrokes inside one frame make it treat the DOM as an external override, rewrite the editor and collapse the caret to offset 0. Zero-delay typing is the only thing that reaches that window. Generated-by: Claude Code
22819fb to
686105e
Compare
jackwener
left a comment
There was a problem hiding this comment.
I found no blocking issues on 686105e8c514488589d85dc3f25c98cbb3168963.
The test changes keep the user contract intact while removing two automation-only timing assumptions. The real DropdownMenu stamps its 50 ms suppression window on every hide; in a controlled-clock probe through the built Electron app, a reopen inside that window left aria-expanded=false with no menu items, while the same trigger opened after the clock advanced. openPicker therefore retries only the dropped trigger action and still requires the requested menu to become visible. The 20 ms typing delay also remains far faster than ordinary human input while keeping successive synthetic keystrokes out of the composer's one-frame controlled-echo race.
An uncontrolled old-spec control happened to pass 10/10 on this machine, so I did not treat the issue's local failure rate as proof. I independently verified the actual dropped-click branch above, then ran the exact changed spec 10 times: both journeys passed 20/20. The full Desktop dependency/application build, Biome, diff-check, ASF headers, the exact-head hosted test check, and the current-main merge result also passed.
Automated review notice: This comment was posted by an automated review agent operated by WAWQAQ. It is not an independent human review and does not replace one.
Astro-Han
left a comment
There was a problem hiding this comment.
Synthesis at exact head 686105e8c514488589d85dc3f25c98cbb3168963 (686105e) — test(desktop): stop the picker spec racing two upstream guards.
All findings in this comment are from @DSv4F-Qronos-AstroHan independent review at this exact head. I did not read this diff myself; I verified that the current head has not drifted and the exact-head CI status is green (test SUCCESS, MERGEABLE/CLEAN per Luna coordination re-check).
Actual change (per reviewer, 1 file +14/-3)
picker.click()withtoPass({timeout:10_000})retry for DropdownMenu 50ms reopen吞点击竞态,page.keyboard.type(DRAFT,{delay:20})人速输入避免同帧双键重写 caret。toPass10s 超时仍失败,不掩盖真实失败;delay:20> 16.7ms/帧保证单键单帧;无其他 spec 使用该 picker,无一致性缺口。
Gate
- Code: GO, no P0–P2 (1×P3 low risk:
openPickerusespage.getByRole('menuitem').first()global query, but picker is sole menu source in this spec). - CI: exact-head
testSUCCESS (13m20s), MERGEABLE/CLEAN, reviews: priorjackwenerAPPROVED at this head is automated and does not count as independent human review. MERGEABLE/CLEAN,REVIEW_REQUIRED— requires human formal Review before merge.
What this synthesis could not verify
- No local Electron E2E run on this head by synthesizer; relied on reviewer's code-path deduction and hosted CI. Storybook visual state not re-run here.
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
Fixes #4224
new-task-draft-target.spec.tsfails every run on macOS: after choosing 无项目 it reopens the workspace picker, and that click opens nothing, so the wait for the Project menu item times out at 30s. Two separate races were in the way; both live in@astryxdesign/core, and neither is reachable at human speed.The reopen.
DropdownMenudrops a trigger click that lands within 50ms of the menu hiding:The guard exists so iOS Safari's light dismiss — pointerdown hides the menu, then the trigger's own click arrives — cannot instantly reopen it. But
usePopover({ onHide: handleLayerHide })stamps that timestamp on every hide, so choosing a menu item arms it the same way. Whether the reopen survives then depends on how long the assertions between the two clicks happen to take. The spec now waits for the menu it asked for instead of assuming the click took, which also holds if that 50ms ever changes.The typing. With the reopen fixed, a ~4% failure the first one had been masking surfaced: the draft came back scrambled (
"idraft written before choosing a project","drafet written before choosing a project"— one character displaced to an earlier offset).ChatComposerInputabsorbs exactly one echo of its ownonChange; a second keystroke inside the same frame overwrites that marker, so the pending echo is read as an external override:A keystroke landing between that rewrite and the caret restore goes in at offset 0.
page.keyboard.typewith no delay is the only thing that types two characters inside one frame, so the spec now types at 20ms/char.Before / after, 50 runs of this spec each:
(The 50-run "before" is already past the reopen fix — with the original spec the failure is 100%, not 4%.)
Both are test-side fixes on purpose. The dropdown guard is load-bearing on iOS Safari, and the composer's echo window is one frame: no user clicks a trigger 50ms after picking from its menu, and none types two characters in 16ms.
Generative tooling: Claude Code (Opus 5) investigated and wrote this change; the commits carry a
Generated-bytrailer.