e2e: give the calendar tests the dated cards their grids require #185

Merged
Grandiras merged 1 commit from fix/e2e-calendar-empty-state into main 2026-08-29 18:27:11 +00:00
Owner

boards.spec.js:165 ("the nav switches boards…") and calendar.spec.js:515 ("a six-week month fits a short window…") have been failing deterministically on main. The app is right; the tests were wrong.

Diagnosis. Since the calendar's emptiness check became month-scoped (94bb97e, #85), a month with nothing due renders its empty state instead of the grid — .calendar-grid / .calendar-week are not merely empty but absent. Both tests waited on those elements without ever minting a dated card, which is exactly the fresh-stack rule docs/testing.md documents (and mobile.spec.js once broke the same way). CI cannot run the e2e suite, so the break was silent. The empty state itself is deliberate, and the entrance never gates it, so there is no stuck-invisible bug in the app.

Fixes

  • Six-week test: computes the nearest six-Monday-row month the way CalendarMonth does (in UTC), dates one card there, and pages to it on the heading — the months walked through on the way have no grid to wait for. Its overflow measurement also stopped racing the entrance: the cascade lifts each week from 14px below its place (precisely --entrance-rise, precisely the overflow it then flaked with under full-run load), so the measurement finishes the animations first.
  • Board-switch test: dates a card on its new board so the switched-to calendar has rows for the entrance reveal the test pins — on an empty board there is nothing gated to observe. The card is deleted before the board in the finally, because a board holding cards refuses deletion by design (BoardNotEmptyException).
  • docs/testing.md: the fresh-stack paragraph now names the calendar as its sharpest case.

Verified: full Playwright suite 146/146 against a clean --force-recreate stack built from main; unit suite 448/448. (One unrelated flake of access.spec.js:192 appeared in one intermediate run and passed alone and in the final full run — the known circuit-attach race class from testing.md.)

🤖 Generated with Claude Code

`boards.spec.js:165` ("the nav switches boards…") and `calendar.spec.js:515` ("a six-week month fits a short window…") have been failing deterministically on `main`. **The app is right; the tests were wrong.** **Diagnosis.** Since the calendar's emptiness check became month-scoped (94bb97e, #85), a month with nothing due renders its empty state *instead of* the grid — `.calendar-grid` / `.calendar-week` are not merely empty but absent. Both tests waited on those elements without ever minting a dated card, which is exactly the fresh-stack rule `docs/testing.md` documents (and `mobile.spec.js` once broke the same way). CI cannot run the e2e suite, so the break was silent. The empty state itself is deliberate, and the entrance never gates it, so there is no stuck-invisible bug in the app. **Fixes** - **Six-week test**: computes the nearest six-Monday-row month the way `CalendarMonth` does (in UTC), dates one card there, and pages to it on the heading — the months walked through on the way have no grid to wait for. Its overflow measurement also stopped racing the entrance: the cascade lifts each week from 14px below its place (precisely `--entrance-rise`, precisely the overflow it then flaked with under full-run load), so the measurement finishes the animations first. - **Board-switch test**: dates a card on its new board so the switched-to calendar has rows for the entrance reveal the test pins — on an empty board there is nothing gated to observe. The card is deleted before the board in the `finally`, because a board holding cards refuses deletion by design (`BoardNotEmptyException`). - **`docs/testing.md`**: the fresh-stack paragraph now names the calendar as its sharpest case. **Verified**: full Playwright suite 146/146 against a clean `--force-recreate` stack built from `main`; unit suite 448/448. (One unrelated flake of `access.spec.js:192` appeared in one intermediate run and passed alone and in the final full run — the known circuit-attach race class from testing.md.) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
e2e: give the calendar tests the dated cards their grids require
All checks were successful
CI / build (pull_request) Successful in 39s
6e03a3bb3c
boards.spec.js:165 and calendar.spec.js:515 went quietly red when the
calendar's emptiness check became month-scoped (94bb97e, #85): a month
with nothing due renders its empty state *instead of* the grid, so
.calendar-grid and .calendar-week are not merely empty but absent —
and both tests waited on them without ever minting a dated card. CI
cannot run the e2e suite, so nothing noticed. The app is behaving as
designed (the empty state is deliberate and the entrance never hides
it); the tests broke testing.md's own fresh-stack rule.

- The six-week test now computes the nearest six-Monday-row month the
  way CalendarMonth does (in UTC), dates one card there, and pages to
  it on the heading rather than on a grid the empty months in between
  do not have. Its overflow measurement also stops racing the entrance:
  the cascade lifts each week from 14px below its place (precisely
  --entrance-rise, precisely the overflow it flaked with), so the
  animations are finished before measuring.
- The board-switch test dates a card on its new board so the switched-to
  calendar has rows for the entrance reveal it pins — on an empty board
  there is nothing gated to observe. The card is deleted before the
  board: a board holding cards refuses deletion by design.
- testing.md's fresh-stack paragraph now names the calendar as its
  sharpest case, so the next spec does not re-learn this.

Full suite: 146/146 against a clean main-built stack; unit 448/448.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator

🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 Reviewing this PR — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/414); the reply will link the full session transcript. <!-- claude-run:pr_review --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-185/run-414.md) — updating every ~5 minutes while the task runs.
claude-reviewer left a comment

✅ Verdict: approve — no blocking issues found.

Verified the diagnosis and fix against the actual source rather than taking the PR description on faith:

  • Calendar.razor:770 defines Today as DateOnly.FromDateTime(DateTime.UtcNow), confirming the six-week test's UTC-based month math is the right basis for computing the same month the server would.
  • CalendarMonth.GridDays computes weeks = (span + 6) / 7 where span = WeekdayIndex(first) + daysInMonth, and WeekdayIndex is ((int)DayOfWeek + 6) % 7 (Monday-first). The test's Math.ceil((offset + days) / 7) with offset = (first.getUTCDay() + 6) % 7 is the exact same formula, so the six-week month the test locates is guaranteed to match production.
  • createDatedCard/dayThisMonth added to boards.spec.js are a verbatim copy of the ones already in calendar.spec.js, consistent with this suite's existing convention of each spec file being self-contained (no shared helpers module).
  • deleteCard's button:has-text("Delete") then button:has-text("Yes, delete") sequence looked at first like it could hit Playwright's strict-mode multi-match (since has-text is substring matching and "Yes, delete" contains "delete"), but CardModal.razor renders the two states via mutually exclusive @if/@else blocks, so only one match ever exists at a time — and the same two-line pattern is already used identically in board.spec.js, boards.spec.js (existing test), share.spec.js, and calendar-all.spec.js.
  • The board-switch test correctly dates the card only after switching onto the new board's /board/{id} (confirmed by tracing the test flow), so createDatedCard operates on the right board, and the calendar navigation afterward switches to that same board's calendar.
  • The document.getAnimations().forEach(a => a.finish()) addition directly targets the described entrance-animation race in the overflow measurement, with a try/catch correctly guarding against finish() throwing on non-finite animations.

No correctness issues found. The docs update is a scoped addition to the existing fresh-stack paragraph and remains accurate. This is a well-verified fix — good to merge.


⏱ 1m 31s · 17 turns · tokens: 29.2k in / 6.5k out (+765.7k cache-read)
📜 Full session transcript

✅ **Verdict: approve** — no blocking issues found. Verified the diagnosis and fix against the actual source rather than taking the PR description on faith: - `Calendar.razor:770` defines `Today` as `DateOnly.FromDateTime(DateTime.UtcNow)`, confirming the six-week test's UTC-based month math is the right basis for computing the same month the server would. - `CalendarMonth.GridDays` computes `weeks = (span + 6) / 7` where `span = WeekdayIndex(first) + daysInMonth`, and `WeekdayIndex` is `((int)DayOfWeek + 6) % 7` (Monday-first). The test's `Math.ceil((offset + days) / 7)` with `offset = (first.getUTCDay() + 6) % 7` is the exact same formula, so the six-week month the test locates is guaranteed to match production. - `createDatedCard`/`dayThisMonth` added to `boards.spec.js` are a verbatim copy of the ones already in `calendar.spec.js`, consistent with this suite's existing convention of each spec file being self-contained (no shared helpers module). - `deleteCard`'s `button:has-text("Delete")` then `button:has-text("Yes, delete")` sequence looked at first like it could hit Playwright's strict-mode multi-match (since `has-text` is substring matching and "Yes, delete" contains "delete"), but `CardModal.razor` renders the two states via mutually exclusive `@if`/`@else` blocks, so only one match ever exists at a time — and the same two-line pattern is already used identically in `board.spec.js`, `boards.spec.js` (existing test), `share.spec.js`, and `calendar-all.spec.js`. - The board-switch test correctly dates the card only after switching onto the new board's `/board/{id}` (confirmed by tracing the test flow), so `createDatedCard` operates on the right board, and the calendar navigation afterward switches to that same board's calendar. - The `document.getAnimations().forEach(a => a.finish())` addition directly targets the described entrance-animation race in the overflow measurement, with a `try/catch` correctly guarding against `finish()` throwing on non-finite animations. No correctness issues found. The docs update is a scoped addition to the existing fresh-stack paragraph and remains accurate. This is a well-verified fix — good to merge. --- ⏱ 1m 31s · 17 turns · tokens: 29.2k in / 6.5k out (+765.7k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/pr-185/run-414.md) <!-- claude-verdict:approve --> <!-- claude-reviewed-head:6e03a3bb3c8cb6973e65ca3807776407d60b31dd -->
Grandiras deleted branch fix/e2e-calendar-empty-state 2026-08-29 18:27:11 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/Ponente!185
No description provided.