From 425284aa2c25463263a8dd12c9ebd9cfa2d6fe9c Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Fri, 30 Oct 2026 09:58:44 +1100 Subject: [PATCH] test(desktop): measure inline video controls against their player (#8683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `video-attachment.spec.ts:856` (inline video hover reveals a timeline without a second play control) fails in about 1 of 15 runs. This change fixes the test only. The test reads the inline controls' page `y` at rest and again after hovering, then asserts the two differ by less than 0.5px, so the controls don't slide in. In failing runs the whole message row moves 1px in the timeline between the two reads. The controls stay in the same place relative to their player: ``` pass {"restControls":529,"hoverControls":529,"restPlayer":392,"hoverPlayer":392} fail {"restControls":529,"hoverControls":528,"restPlayer":392,"hoverPlayer":391} ``` Now the test measures the controls' offset from their `video-player` in a single `evaluate`, so it reads both values in the same frame. Moving the row no longer matters, and a real slide-in still fails. ### Why it showed up now On [buzz #8680](https://github.com/block/buzz/pull/8680), Flake Check failed 6 of 14 Playwright shard runs on this test. That PR edits shared helpers in the same spec file, so `scripts/flake-check.mjs` selects the whole file and repeats every test in it 10 times. The test hadn't changed on main since September. It just had never been repeated before. ## Testing - Reproduced on clean `main` with `playwright test --project=smoke video-attachment -g "inline video hover reveals" --repeat-each 15`: 1 failed, 14 passed. - With this change: `--repeat-each 40` gave 40 passed. The full `video-attachment` spec also passed, 13 of 13. - To confirm the test can still fail, I temporarily added `translate-y-1 group-hover/video:translate-y-0` to the inline controls. The test failed with `Received: 4`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Matt Toohey Co-authored-by: Jitter <2b2e6415e748c35180847a37aadae06a11e30dddc76b784e7fd9354c4eb42e7a@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 5.5 --- desktop/tests/e2e/video-attachment.spec.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/desktop/tests/e2e/video-attachment.spec.ts b/desktop/tests/e2e/video-attachment.spec.ts index 060d356d28..f274173379 100644 --- a/desktop/tests/e2e/video-attachment.spec.ts +++ b/desktop/tests/e2e/video-attachment.spec.ts @@ -895,18 +895,24 @@ test("inline video hover reveals a timeline without a second play control", asyn ) .toBe("50%"); - const restingControlsBox = await controls.boundingBox(); + // The timeline can shift the whole row by a pixel while the pointer moves + // in, so measure the controls against their own player in a single frame. + const controlsOffset = () => + controls.evaluate((element) => { + const playerTop = element + .closest('[data-testid="video-player"]') + ?.getBoundingClientRect().top; + return element.getBoundingClientRect().top - (playerTop ?? Number.NaN); + }); + const restingControlsOffset = await controlsOffset(); const restingIconTransform = await centerIcon.evaluate( (element) => window.getComputedStyle(element).transform, ); - expect(restingControlsBox).not.toBeNull(); await expect(controls).toHaveCSS("opacity", "0"); await surface.hover(); await expect(controls).toHaveCSS("opacity", "1"); - const hoveredControlsBox = await controls.boundingBox(); - expect(hoveredControlsBox).not.toBeNull(); expect( - Math.abs((hoveredControlsBox?.y ?? 0) - (restingControlsBox?.y ?? 0)), + Math.abs((await controlsOffset()) - restingControlsOffset), ).toBeLessThan(0.5); await expect .poll(() =>