test: stabilize flaky widget-tag streaming assertion (#3314) - #3378
Conversation
Wrap the negative queryByText assertion in waitFor so React flushes the streaming state update before the assertion fires on slow CI runners. Closes #3314
UX Review (Fable 5) — ✅ PASSAdvisory UX-level review of UX-Verdict: PASS Test-only change — one assertion wrapped in [UX-REVIEWED] 2c405b2 |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Opus 4.8 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — ✅ PASSAdvisory design-level review of Design-Verdict: PASS Root-cause fix for a diagnosed CI race, using the repo's documented flake remedy and the file's own existing pattern; semantics preserved. [DESIGN-REVIEWED] 2c405b2 |
iamwhatever
left a comment
There was a problem hiding this comment.
Tier 1 auto-approve: test stabilization (1 file). Criteria: no conflict, no requested changes, no security surface, AI reviewers green. Category: flaky test fix — stabilizes widget-tag streaming assertion timing (#3314 follow-up).
kirodotdev#3378) Wrap the negative queryByText assertion in waitFor so React flushes the streaming state update before the assertion fires on slow CI runners. Closes kirodotdev#3314
test: stabilize flaky widget-tag streaming assertion
Problem
MochiChatPanel.coverage.test.tsx > ChatPanel streaming footer > drops a half-arrived widget tag rather than showing its markupfails intermittently in CI while passing locally. Observed on PR #3302, run 31710742636, shardFrontend Tests (4)at headcba9e9778— a PR whose diff cannot reach this test's code paths.Why it matters
A shard that fails on a file the diff cannot reach costs every unrelated PR a re-run and trains reviewers to distrust red CI.
Fix (symptom → root cause → change)
<mcwidgettag, the test awaits the positive assertion (findByText('Building it now'), which waits) but then immediately fires the negative assertion with a synchronousqueryByText(/mcwidget/). The streamed-state commit that strips the partial tag is asynchronous; on a slow runner the assertion runs before React flushes, still sees the pre-strip markup, and fails.waitFor—await waitFor(() => expect(screen.queryByText(/mcwidget/)).not.toBeInTheDocument())— so the assertion polls until React commits. This is the determinism-conventions remedy for this flake class (poll, never sleep/rerun/relax) and the same pattern this file already uses for its other post-async negative assertion ("replaces the streamed text with the committed message").The assertion semantics are unchanged: if the panel ever rendered the partial widget markup persistently,
waitFortimes out and the test still fails.Tests
This PR is itself a test change.
MochiChatPanel.coverage.test.tsxpasses 82/82; full frontend suite 17990 passed / 0 failed on the branch;npx tsc -bclean.Manual verification
N/A — unit coverage sufficient; the change is confined to one test assertion.
Screenshots
N/A — no user-visible UI change.
Closes #3314