test: stabilize flaky calendar-1-single-booking Playwright test#467
Merged
turegjorup merged 1 commit intoMay 27, 2026
Merged
Conversation
Replace whole-DOM getByText("Ledigt") scan with a specific
.status locator and add a .room-info visibility anchor before
the assertion so Playwright doesn't poll an un-rendered tree.
Mirrors the pattern of the passing calendar-0-single-booking
sibling test (line 202).
The previous form was flaky: getByText with toHaveCount(1)
fails fast if .status briefly shows "Optaget" during the
mount-then-effect re-render window (currentTime initializes
from useState(dayjs()) before the page.clock.install propagates
into the React tree). toHaveText keeps polling the same element
until it settles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tuj
approved these changes
May 27, 2026
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.
Why
calendar-1-single-booking: ui testsinassets/tests/template/template-calendar.spec.jsis intermittently flaky — observed failing then passing on a Playwright rerun of the exact same commit, with no template/JSX changes between runs.Root cause
The render that produces "Ledigt" / "Optaget" depends on
currentTime, which the component initializes viauseState(dayjs())(line 70 ofcalendar-single-booking.jsx). AuseEffectthen callsintervalChecking()which resetscurrentTimeto the (mocked) clock value and starts a 60ssetInterval. Between mount and the first effect, the rendered.statustext can briefly reflect non-mocked time. TheinstantBookingEnabledpath also kicks off an asyncfetchto/actionwhose latency varies under CI load.The previous assertion form amplified that race:
page.getByText("Ledigt")scans the whole DOMpage.locator(".status")pins to one elementawait expect(page.locator(".room-info")).toBeVisible()toHaveCount(1)+toBeVisible()fails fast if the text is briefly absent or duplicatedtoHaveText("Ledigt")keeps polling that one element until it settlestoHaveTextagainst a specific locator is the auto-retrying pattern Playwright already documents for time-sensitive UI, and matches the passingcalendar-0-single-bookingsibling test (line 202).What
test("calendar-1-single-booking: ui tests", async ({ page }) => { await fixTime(page); await page.goto("/template/calendar-1-single-booking"); - await expect(page.getByText("Ledigt")).toHaveCount(1); - await expect(page.getByText("Ledigt")).toBeVisible(); + await expect(page.locator(".room-info")).toBeVisible(); + + const status = page.locator(".status"); + await expect(status).toHaveText("Ledigt"); await page.clock.runFor(61000); - await expect(page.getByText("Optaget")).toHaveCount(1); - await expect(page.getByText("Optaget")).toBeVisible(); + await expect(status).toHaveText("Optaget"); });No production code touched.
Why not patch the component instead
Lazy-initializing
currentTimefrom inside the effect (e.g.useState(null)then set on mount) would remove the brief "real time" render window, but risks the passingcalendar-0-*sibling tests that already rely on the current behavior. Production change with a wider blast radius is the wrong tool for a test-side timing assumption — keep the fix where the problem is observed.Test plan
calendar-*tests (they don't share the assertion form being changed)🤖 Generated with Claude Code