From 61144be1e16aca03efda378f0b515bc4a675b701 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Thu, 5 Nov 2026 14:40:09 +1100 Subject: [PATCH] test(sidebar): wait for the rolled-back row to leave Starred before collapsing Work WebKit's navigation-groups.spec.mjs:650 "dismissing a failed move restores keyboard focus to its placement or a surviving row" failed once, at the `expect(beta).toBeHidden()` after clicking Work's header (https://github.com/block/buzz-app/actions/runs/41946923047/job/126981730084), on a branch that doesn't touch the sidebar. Cause: the failed move's alert arrives with the rollback render. The optimistic copy of the row in Starred is then an AnimatePresence exit: it stays laid out (inert, fading) until the exit ends, and the row re-enters Work at once. The journey's barrier, Work's beta row being visible, passes as soon as that row mounts at low opacity, so the click on Work's header can start before the Starred copy leaves. Its removal moves Work's header up by a row. In the CI trace the press landed on the header (two beta rows in the DOM) and the release on the Beta row that slid under it, so the browser fired no click on the header. Playwright's hit-target check only covers the first event of a click. The trace shows the section never collapsed, the first `details` kept `open`, and the final screenshot shows the pointer resting on Beta. Fix: after the alert, wait until the sidebar holds exactly one beta row, so the Starred exit has finished before the journey acts on the layout. No assertion, timeout or retry changes; test-only. Validation: with requestAnimationFrame held from the 502 until the header press and a 300 ms press-to-release delay, the journey failed 20/20 (Chromium and WebKit) with the CI signature without this change, and passed 20/20 with it. navigation-groups.spec.mjs in full, --repeat-each=10 --retries=0, passed 100/100 in WebKit and 100/100 in Chromium. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Matt Toohey --- tests/browser/navigation-groups.spec.mjs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/browser/navigation-groups.spec.mjs b/tests/browser/navigation-groups.spec.mjs index acd6cb424d..6cbb4e180c 100644 --- a/tests/browser/navigation-groups.spec.mjs +++ b/tests/browser/navigation-groups.spec.mjs @@ -671,6 +671,13 @@ test("dismissing a failed move restores keyboard focus to its placement or a sur .getByRole("menuitemradio", { name: "Starred", exact: true }) .click(); await expect(error).toContainText("Relay request failed (502)"); + // The alert arrives with the rollback, but the optimistic Starred copy of + // the row stays laid out while it fades out, and its removal moves every + // section below it. Wait for the exit, or a press on Work's header can + // finish on the row that slid under it, which is no click. + await expect(sidebar(page).locator('[data-channel-id="beta"]')).toHaveCount( + 1, + ); await expect(beta).toBeVisible(); }; const dismiss = async () => {