Affected service
UI — ui/playwright/tests/chat/checkpoints.spec.ts
Description
chat: the mark names itself, carries its controls, and opens its record is flaky. It fails on the first attempt and passes on retry, so the run is reported green with 2 flaky and the failure is easy to miss.
The failing step is and the mark's own delete asks first, then takes it:
Error: locator.click: Test timeout of 30000ms exceeded
113 | await expect(page.getByText("Delete this snapshot?")).toBeVisible();
> 114 | await page.getByRole("button", { name: "Cancel" }).click();
115 | await expect(dividers(page)).toHaveCount(1);
at ui/playwright/tests/chat/checkpoints.spec.ts:114:56
Cause
Two components render a confirmation with the title Delete this snapshot?:
ui/src/components/chat/CheckpointDivider.tsx — the divider's own delete
ui/src/components/chat/SnapshotDetailsModal.tsx — the dialog's delete
The step immediately before presses Escape to close the dialog and asserts snapshot-details-body has gone. It then opens the divider's confirmation and reaches for getByRole("button", { name: "Cancel" }) across the whole page. While the dialog is still closing, that label matches a control that is on its way out and never becomes clickable, so the click waits out the full timeout.
Both confirmations already give their ok button a data-testid — chat-checkpoint-delete-confirm-${checkpointId} and snapshot-details-delete-confirm. Neither gives one to its cancel button, which is why the spec has to fall back to a label that is not unique.
The same page-wide lookup appears twice in the spec, at lines 114 and 213, for the two different confirmations.
Suggested fix
Give each cancel button the data-testid its ok button already has, and have the spec use it:
// CheckpointDivider.tsx
cancelButtonProps={{ "data-testid": `chat-checkpoint-delete-cancel-${checkpointId}` }}
// SnapshotDetailsModal.tsx
cancelButtonProps={{ "data-testid": "snapshot-details-delete-cancel" }}
That keeps the assertion deterministic rather than raising the timeout, and it matches the pattern the confirm buttons already set.
Reproduction
Run the chat suite on Chromium. It reproduces intermittently and more readily on a Linux CI runner than on a laptop, since the flake is a race with the dialog's close animation.
🤖 written by Claude
Affected service
UI —
ui/playwright/tests/chat/checkpoints.spec.tsDescription
chat: the mark names itself, carries its controls, and opens its recordis flaky. It fails on the first attempt and passes on retry, so the run is reported green with2 flakyand the failure is easy to miss.The failing step is
and the mark's own delete asks first, then takes it:Cause
Two components render a confirmation with the title
Delete this snapshot?:ui/src/components/chat/CheckpointDivider.tsx— the divider's own deleteui/src/components/chat/SnapshotDetailsModal.tsx— the dialog's deleteThe step immediately before presses
Escapeto close the dialog and assertssnapshot-details-bodyhas gone. It then opens the divider's confirmation and reaches forgetByRole("button", { name: "Cancel" })across the whole page. While the dialog is still closing, that label matches a control that is on its way out and never becomes clickable, so the click waits out the full timeout.Both confirmations already give their ok button a
data-testid—chat-checkpoint-delete-confirm-${checkpointId}andsnapshot-details-delete-confirm. Neither gives one to its cancel button, which is why the spec has to fall back to a label that is not unique.The same page-wide lookup appears twice in the spec, at lines 114 and 213, for the two different confirmations.
Suggested fix
Give each cancel button the
data-testidits ok button already has, and have the spec use it:That keeps the assertion deterministic rather than raising the timeout, and it matches the pattern the confirm buttons already set.
Reproduction
Run the chat suite on Chromium. It reproduces intermittently and more readily on a Linux CI runner than on a laptop, since the flake is a race with the dialog's close animation.
🤖 written by Claude