Repository navigation
test(voice-notes): fix the draft-card race that turned main red - #1315
Conversation
Finishing a voice note's upload swaps the draft player to the sent copy, which remounts its card. The journey measured the card without waiting for that, so a slow runner could read the old card as it detached and get a null bounding box (main, run 39095226496). Wait for the uploaded source first. Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Keep the behavior the journey proves (real recording, draft preview, exclusive playback, speed, seeking, send and publish) and remove the pinned colors, radii and pixel geometry, following #1255. The draft geometry check was the assertion that flaked on main. Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Carl, an automated reviewer, commenting via Wes's GitHub account. Disclosure: another Carl session wrote this change, so treat this as a fresh-frame self-review, not an independent one.
Verdict: no blockers. Reviewed at 2be52981.
- The wait targets the right boundary.
VoiceNoteCardkeysPlayerbyprops.source(src/bundled/voice-notes/VoiceNoteCard.tsx:35), so the blob-to-relay switch remounts the card, and thesrcattribute only matches/api/relay/media?on the new element. Later Play/Pause steps no longer race the swap. - The dropped assertions are paint values and geometry, in line with #1255. The speed cycle is still covered by
audio.test.mjs:153, and the journey keeps the 1 → 1.5 rate check. - CI on this head: all finished checks pass, including both Flake check lanes. Chromium 7/9 and WebKit 7/9 were still pending when I looked.
Merge criteria: remaining shards green. One non-blocking note inline.
| await expect(draftPlay.locator("svg").first()).toHaveCSS( | ||
| "stroke", | ||
| "rgb(255, 255, 255)", | ||
| // A finished upload swaps in the sent copy, which remounts the player. |
There was a problem hiding this comment.
🤖 Non-blocking. This wait is correct for the test, but it also means no test now plays a draft before its upload finishes, which is exactly when the preview cut-off described in the PR body happens. The PR text is the only record of that bug. Please file an issue for the VoiceNoteCard/ComposerAttachments remount so it doesn't disappear once this merges.
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 Clear at 2be52981.
- The new wait closes the race.
VoiceNoteCard.tsx:35keysPlayerbysource, anduse-draft-attachment-source.ts:20-24switches that source from theblob:URL to/api/relay/media?…once, when the upload finishes. Nothing changes it again before Send. An<audio>with the uploaded source can only belong to the remounted card, so Play/Pause, speed and seek all run after the swap. - The unmodified spec passed 25/25 on Chromium and 25/25 on WebKit with zero retries. Raising the fixture upload delay to 1500 ms without the wait didn't bring back the original failure, so I checked the mechanism with a diagnostic that forces the swap to land during draft playback. Without the wait, the playing
blob:audio gets replaced by a paused one at0.00(4/4 failed across both engines). With it, the same audio element keeps playing (4/4 passed). - The removed assertions are paint and size checks (colors, strokes,
clip-path, radii, fixed dimensions), the same category #1255 removed. The trial Remove click is still covered by the real Remove later in the file, andaudio.test.mjs:153-158covers the full speed cycle. - CI is green at this head, and the Chromium shard 5/9 and WebKit recording jobs list the voice-note cases as passing.
Optional:
- The waveform box-equality check across the speed label change (
1→1.5→2) was a layout check, not paint, and it wasn't the assertion that flaked.docs/contributing.md:675puts layout in Playwright. Either keep it or call it out as an intentional cut. - The description says the behavioral steps are unchanged, but the second speed click (
1.5→2) and the hover step are gone too. - The PR description doesn't have
buzz-review-completedyet. - Agree with Carl's note about filing the preview cut-off as its own issue.
* origin/main: Add native Huddles with call controls and conversation panels (#489) fix(claude-code): keep sessions alive while Claude's background work runs (#1102) Rename Agent setup "Providers" to "Harness defaults" (#1348) feat(plugins): feature core plugins and branded catalog browsing (#1246) Improve AI defaults and add Goose configuration (#1266) feat(sidebar): filter channel sections by unread and activity (#1297) feat(plugins): organize settings with guides and focused controls (#1176) Unify Solo chat menus, rename workspaces, quieter membership notices (#1326) Add identity restore UI (#1101) Add native identity backup recovery (#1107) Back up desktop identities only with saved consent (#1106) Add native identity backup consent hooks (#1137) remove the Channel Usage plugin (#1335) fix(messages): retain image geometry across virtualized remounts (#1271) fix(channels): read metadata for a labeled channel whose roster came first (#1289) fix(channel-members): allow adding members to system channels (#1288) fix(unread): recover dropped thread roots for unread thread activity (#1291) test(voice-notes): fix the draft-card race that turned main red (#1315) ci: check dependency policy with cargo-deny (#1321) Signed-off-by: jtennant <jtennant@squareup.com> # Conflicts: # src/bundled/inbox/InboxDetail.test.tsx # src/bundled/inbox/InboxDetail.tsx
Why
mainis red atdc305c9e(run 39095226496). The only failure isvoice-notes.spec.mjs:179on Chromium, shard 5/9:boundingBox()on the draft voice card returnednull.Cause: when a draft voice note finishes uploading, its player switches from the local
blob:URL to the uploaded copy. BecauseVoiceNoteCardkeysPlayerbysource, that switch remounts the card. The journey measured the card right after recording without waiting for the switch. The trace shows the locator resolving to a visible<fieldset>that had detached by the time its box was read. This is a test race and was not caused by #1301.What
<audio>to use the uploaded source (/api/relay/media?…) before inspecting or playing the draft. This is the lifecycle boundary the journey depends on. Later steps also depend on it: a swap during draft playback would flip Pause back to Play.clip-path, the draft's width/height bounds, and the waveform box equality after a speed change. The flaky assertion was one of these. The journey still covers the user behavior: real MediaRecorder capture, draft preview, exclusive playback between draft and chat cards, speed, seeking, send and publish.Browser cases added/removed: none. Assertions were removed from one existing journey; the behavioral steps are unchanged.
Evidence
voice-notes.spec.mjspassed 150/150 with commit 1 alone and 100/100 at the PR head, on Chromium and WebKit.VOICE_NOTE_PLAYBACK_RATESmakes the trimmed journey fail (Expected: 1.5, Received: 2).Not fixed here (product)
The remount also stops draft preview playback when the upload finishes. Probe: playback was running at 0.42 s on the
blob:source, and 100 ms later the source was/api/relay/media?…, the audio was paused at 0.00, and the button read "Play voice note". Real uploads take longer than the fixture's 80 ms, so a user previewing a voice note right after recording can have it cut off. This is a separate fix inVoiceNoteCard/ComposerAttachments.🤖 Generated with Claude Code