Repository navigation
test(desktop): wait on real readiness signals in audience and community-rail specs - #9277
Merged
Merged
Conversation
Fixes two Desktop E2E flakes in
desktop/tests/e2e/persistent-agent-audience.spec.ts.
1. `a manual mention persists when automatic mentions are enabled`:
`locator.fill("follow up")` failed because message-input was not
editable.
Root cause (from the code and the CI symptom; not reproduced
locally): the test sends with a 1.5 s mock send delay. For that
whole delay the composer is submit-locked and its editor is
contenteditable="false". The lock is React state, so it renders a
frame after Enter. The test's last checks before the fill could
both pass before that frame. One polls the outgoing mention, and the
e2e bridge logs a command when it is invoked, before the delay. The
other is the contenteditable="true" wait. The fill then ran inside
the lock. Playwright's fill rejects a contenteditable="false"
element instead of waiting, so it failed outright.
Fix: after Enter, wait for the full send cycle. That is
data-submit-locked "true", then contenteditable "false", then
data-submit-locked "false", then contenteditable "true". Only then
assert on the editor. The deterministic 1.5 s delay keeps the locked
state long enough to observe. The existing assertions are unchanged.
2. `the mention setting is reachable and operable by keyboard`: the
thread composer's mention autocomplete never became visible.
Root cause (likely; not reproduced locally): opening a thread by URL
mounts both the channel composer and the thread composer.
useComposerAutofocus focuses whichever mounts first. TipTap defers
focus() by a frame. A click and fill that land before that deferred
focus lose it, and the focus-gated mention menu unmounts.
Fix: a readyThreadComposerInput() helper waits for the thread
editor to be editable and for exactly one message-input to hold
focus, so the app's own autofocus has landed. The test acts only
after that. Test 1 uses the helper too, since it opens the thread
the same way.
Verified locally (Playwright smoke project, e2e build). I could not
reproduce either flake before the fix, even with CPU throttled 4x and
8x. After the fix:
- both tests, 40 repeats each at 10 workers: 80/80 passed
- whole spec: 35/35 passed
- second independent rerun at 8 workers: both tests passed in all
5 repeats of the full highlight, audience and community-rail specs.
The four desktop flake tests from this series alone, 10 repeats
each: 40/40. In the same run, the untouched test "the mention button
preserves manual rementions after undo until explicitly readdressed"
failed 3/5 (a menu item kept detaching). A baseline build failed it
4/5. It is pre-existing and out of scope here.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: mtoohey <mtoohey@squareup.com>
(cherry picked from commit 3653b2749353862551a036d6e09c8a86621b09df)
…witch Fixes the Desktop E2E flake in `community rail > does not repair a remembered channel until live validation succeeds` (desktop/tests/e2e/community-rail.spec.ts). In that flake, `expect(page).not.toHaveURL(/#\/channels\/general$/)` failed right after the click on community B. Root cause (confirmed): the assertion only held before the switch had run. switchCommunity (useCommunityNavigationTransitions.ts) runs inside a view transition. Its callback writes B's remembered channel into the hash (replaceCommunityDestinationRoute) and then activates B. That lands a few frames after the click returns. By design, the URL is then #/channels/general. AppShell keeps that route until a live channel read succeeds, and only then repairs a channel missing from the list to Home. So the URL check passed only when its first poll beat the view transition. 9547891 asserted toHaveURL(general) at this point. 631b05c inverted it, which made the check depend on timing. Reproduced on the old spec: 21/40 failures at 14 workers. Fix: wait for B's rail button to have aria-current="true", which means the switch has finished. Then assert the URL is #/channels/general, the kept route. After live validation repairs storage to Home, also assert the URL has left #/channels/general. The product is unchanged. Verified locally (Playwright smoke project, e2e build): - the test, 40 repeats at 14 workers: 40/40 passed - whole spec: 27/27 passed at 4 workers - second independent rerun at 8 workers: passed in all 5 repeats of the full highlight, audience and community-rail specs. The four desktop flake tests from this series alone, 10 repeats each: 40/40. In the same run, the untouched test "enters a remembered channel before live validation completes" failed 2/5. It requires the channel to render within 700 ms, ahead of an 800 ms delayed read, which a loaded runner can exceed. A baseline build failed it 5/5. It is pre-existing and out of scope here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: mtoohey <mtoohey@squareup.com> (cherry picked from commit 2ddf8fdf55711bd34f6efe8e31340ba2ed71b98e)
Follow-up to 2ddf8fdf5, from review. After live validation repairs
community B's stored destination to {kind: "home"}, the test checked
only that the URL had left #/channels/general. That passes for any
route, including a wrong one or a transient one. AppShell's repair
calls goHome({ replace: true }), so the test now asserts the Home route,
/#\/$/. The surrounding tests in this spec use the same pattern.
Falsified locally: with the repair temporarily sending the app to
#/channels/random instead of Home, the new assertion failed and the
previous not.toHaveURL check passed.
Verified locally (Playwright smoke project, e2e build):
- this test, in the three-spec run, 5 repeats at 8 workers: 5/5
- the same test with the other desktop flake tests, 10 repeats each
at 8 workers: 80/80
- the 9 failures in that three-spec run came only from two untouched,
pre-existing flaky tests. A baseline build fails them as often.
They are community-rail "enters a remembered channel before live
validation completes" and persistent-agent-audience "the mention
button preserves manual rementions after undo until explicitly
readdressed".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: mtoohey <mtoohey@squareup.com>
(cherry picked from commit 4b66818df4411eb6c388ffd9fc080a212603a39b)
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
kazemek21
approved these changes
Nov 9, 2026
kazemek21
left a comment
Contributor
There was a problem hiding this comment.
Kyle reviewed this PR and the Nexus review-tracker notes and approved with no comments.
Posted by Codex (gpt-6.1-sol) on behalf of kylez
wpfleger96
added a commit
that referenced
this pull request
Nov 10, 2026
…e-mode * origin/main: ci(docker): skip relay image publishes for main pushes outside the build context (#9310) Add manual-only relay image publishing (#9303) fix(mobile): bump Flutter to 3.47.9 for Android TLS fix (#9309) Serve video and poster previews for invite links (#9306) docs: point the README to Buzz 1.0 in block/buzz-app (#9296) fix(db): give the replica-fence probe its own pool and instrument it (#9297) fix(relay): never close connections when cross-node fan-out falls behind (#9302) test: fix timing-dependent unit tests in buzz-cli, buzz-agent and buzz-admin (#9273) fix(ci): classify hermit retry timeouts by watchdog kill, not whole seconds (#9274) test(ios): wait for a key, foreground-active window before presenting in RunnerTests (#9275) test(desktop): wait on real readiness signals in audience and community-rail specs (#9277) Signed-off-by: Will Pfleger <wpfleger@block.xyz>
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Split out of the
flakey-mondayflake-fix series. Three Desktop E2E tests inpersistent-agent-audience.spec.tsandcommunity-rail.spec.tsacted on signals that could arrive before the app state they implied (a logged command before the submit lock rendered, a URL check that only held before a view transition landed). They now wait on the readiness signals the product actually exposes. No product code changes.Commits (cherry-picked from
flakey-monday, original messages kept):test(desktop): wait for composer focus and send cycles in audience specstest(desktop): assert the kept remembered route after the community switchtest(desktop): assert Home after repairing the remembered channelRoot cause and fix per test
a manual mention persists when automatic mentions are enabled(desktop/tests/e2e/persistent-agent-audience.spec.ts):locator.fill("follow up")failed becausemessage-inputwas not editable.contenteditable="false". The lock is React state and renders a frame after Enter. The test's last two checks before the fill could both pass before that frame: the outgoing-mention poll (the e2e bridge logs a command when invoked, before the delay) and thecontenteditable="true"wait. Playwright'sfillrejects acontenteditable="false"element outright instead of waiting.data-submit-locked"true",contenteditable"false",data-submit-locked"false",contenteditable"true". Only then assert on the editor. Existing assertions are unchanged.the mention setting is reachable and operable by keyboard(same spec): the thread composer's mention autocomplete never became visible.useComposerAutofocusfocuses whichever mounts first and TipTap defersfocus()by a frame. A click and fill that land before that deferred focus lose it, and the focus-gated mention menu unmounts.readyThreadComposerInput()helper waits for the thread editor to be editable and for exactly onemessage-inputto hold focus, so the app's own autofocus has landed. Both tests use it.community rail > does not repair a remembered channel until live validation succeeds(desktop/tests/e2e/community-rail.spec.ts):expect(page).not.toHaveURL(/#\/channels\/general$/)failed right after the click on community B.switchCommunityruns inside a view transition whose callback writes B's remembered channel into the hash and then activates B, a few frames after the click returns. By design the URL is then#/channels/general, whichAppShellkeeps until a live channel read succeeds and only then repairs to Home. The inverted check from 631b05c passed only when its first poll beat the view transition.aria-current="true"(switch finished), then assert the URL is#/channels/general, the kept route. After live validation repairs storage to Home, assert the Home route/#\/$/(the follow-up commit;not.toHaveURL(general)would have passed for any route, andAppShell's repair callsgoHome({ replace: true })).Related issue
N/A (flake fixes; none found).
Testing
Human testing is still required. This PR does not carry
buzz-review-completed; the author has not yet run these specs themselves on this branch.Verification
Verified locally on the
flakey-mondaybranch before the split (Playwright smoke project, e2e build):#/channels/random, the new assertion failed and the previousnot.toHaveURLcheck passed.Nothing was re-run on this split branch: the workstation was overloaded, so no tests, builds or linters were executed after cherry-picking. CI on this PR is the verification for the split branch.
🤖 Generated with Claude Code