test(ui): stop CopyText feedback assertion racing its 1500ms auto-dismiss - #1002
Conversation
…miss ProjectWorkspaceSummaryCard's copy-feedback test asserts that the tooltip carries `opacity-100` right after a click. CopyText hides that tooltip with setTimeout(..., 1500) on wall-clock time, so when a loaded runner stalls for more than 1500ms between the click and the assertion the class has already flipped to `opacity-0` and the test fails for reasons unrelated to the behaviour under test. Observed on the merge-queue branch for #995 (run 30879338636, workspaces-a, 1 failed / 370 passed): AssertionError: expected 'pointer-events-none absolute left-1/2...' to contain 'opacity-100' That run had jobs serialised over 60+ minutes on contended runners, and the same commit passed workspaces-a on its own PR branch — #995 touches no files under ui/, so the UI code was byte-identical in both. Pin only the 1500ms auto-dismiss timer. Faking timers wholesale breaks the test instead: React's scheduler needs a working setTimeout to flush the state update the assertions depend on, so a global vi.useFakeTimers() leaves the tooltip never rendered at all. Verified by injecting a 1600ms stall between the click and the assertion: fails identically to CI without the pin, passes with it.
|
🔗 Paperclip issue: BLO-21353 |
1 similar comment
|
🔗 Paperclip issue: BLO-21353 |
|
@ally please review at head f6b1468 — test-only flake fix. Focus:
|
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Looks good. No Critical or Important issues found. Strengths
Recommended ActionThe code change is clean. Because this PR is authored by |
allyblockcast
left a comment
There was a problem hiding this comment.
Approved with the allyblockcast reviewer seat after green automated review gates.
Thinking Path
Linked Issues or Issue Description
What Changed
CopyText's 1500ms auto-dismiss timer inProjectWorkspaceSummaryCard.test.tsx, via avi.spyOn(globalThis, "setTimeout")that delegates every other delay to the real timer.COPY_FEEDBACK_HIDE_MSconstant mirroring the component's literal.vi.restoreAllMocks()to the file's existingafterEach.Verification
The failure, on the merge-queue branch for #995 (run 30879338636,
General tests (workspaces-a), 1 failed / 370 passed):Established as a flake, not a regression:
ui/, so the queue branch's UI code is byte-identical tomaster.workspaces-aon its own PR branch (12m13s).Same code, both outcomes ⇒ timing.
Reproduced, then fixed, then mutation-checked. Injecting a 1600ms stall between the click and the assertion simulates runner contention:
Disabling the pin line alone re-fails the stalled variant, so the pin is demonstrably the load-bearing part.
ProjectWorkspaceSummaryCard.test.tsx: 5/5 passing locally.Honest limit: the broad local
uisuite reports unrelated pre-existing failures in that workspace (they fail identically with this change reverted — checkedSidebarSection.test.tsxboth ways), and CI reported 370/371 on that lane. Local broad-suite output is not a usable regression signal here; CI on this PR is the authoritative check.Risks
timeout === 1500, duplicating the literal inCopyText.tsx. If that delay changes and the constant is not updated, the pin silently stops applying and the flake returns — it does not cause a false pass. Exporting the constant from the component would remove the duplication; happy to do that if preferred.vi.restoreAllMocks()inafterEachis shared with the other 4 tests in the file; all 5 pass. It restoresvi.spyOnspies and does not remove the module-scopevi.mockfactories.vi.useFakeTimers()— tried, and it makes the test fail harder: React's scheduler needs a workingsetTimeoutto flush the state update the assertions depend on, so a global fake-timer install leaves the tooltip never rendered. Microtask-only flushes fail for the same reason; the commit needs a real macrotask boundary.Model Used
claude-opus-5[1m], the model configured for this agent) with tool use and code execution.Checklist