4.5.4 Story tests — sprint-scope projection + sprint summary + header + no-active-sprint (component + focused E2E)
Estimate: 20m · Depends on: 4.5.2, 4.5.3
The closing test subtask for the scrum board — the same split Stories 3.1.7 / 3.2.7 / 3.3.7 used: this story ships its OWN component/unit tests + a focused scrum E2E, while the cross-cutting Epic-3 journey (drag + WIP + swimlanes AT SCALE) lives in the Epic-3 test story 3.5 (the at-scale Scrum integration may live in Epic 4's test story 4.7 — the closing test story shipped with 4.7 calls that). The 3.1 API + 3.2/3.3 board are already proven; this proves the sprint-scope + header layer on top.
Component / unit (vitest, real Postgres where DB-touching). The 4.5.2 projection: scrum scope (only active-sprint issues), the kanban no-op (unchanged), no-active-sprint → sprint: null, the SprintSummaryDto aggregates (committed/completed/remaining + columnPoints from SUM/grouped queries, an unestimated sprint → 0s, daysRemaining floored at 0), and that pagination/bounding/swimlane grouping are preserved with the sprint filter (no load-all) — may overlap 4.5.2, keep the integration assertions here. The 4.5.3 header: render of name/goal/dates/time-remaining ("Ended" + normal), the points summary incl. the "—" unestimated presentation, the per-column point pill, and the no-active-sprint empty-state render + Backlog CTA.
E2E (Playwright) tests/e2e/board-scrum.spec.ts. Against a freshly seeded project with a scrum board + an active sprint with points (seed/DB-set the active sprint state for the test — the lifecycle UI is 4.4):
- Header — the sprint header shows name/goal, the date range + time remaining, and the committed/completed/remaining points.
- Scope — only the active sprint's issues appear on the board; an issue not in the sprint is absent; per-column point totals render.
- Move contract — moving a card still transitions its status (3.2 contract) and leaves its sprint unchanged.
- No active sprint — with the sprint completed/none, the board area shows "No active sprint" with the Backlog CTA, not an empty six-column board.
Defers to Story 3.5 (Epic 3) / 4.7 (Epic 4): the combined drag + WIP + swimlanes + scrum journey at scale and the large-active-sprint board/virtualization E2E (this story's scale proof is the 4.5.2 acceptance checks against db:seed:large).
Acceptance criteria
pnpm testcovers the projection (scrum scope, kanban no-op, no-active-sprint, the point aggregates incl. unestimated → 0s,daysRemainingfloor, bounded/paged/swimlane preserved) and the header/empty-state render (incl. "Ended", "—", per-column pill, Backlog CTA).pnpm test:e2e --grep board-scrumruns green over the real stack, asserting: the sprint header (name/goal/dates/remaining + points), sprint scope (only sprint issues + per-column totals), the unchanged move contract (status transitions, sprint unchanged), and the no-active-sprint empty state with the Backlog CTA.- The E2E reuses the real-Postgres harness (
tests/helpers/db.tstruncation) and the seeded project (active sprint state set in the fixture, since the lifecycle UI is Story 4.4); it does NOT duplicate the at-scale combined journey (Stories 3.5 / 4.7).
Context refs
tests/e2e/board-ui.spec.ts(3.2.7) +tests/e2e/board-swimlanes.spec.ts(3.3.7) — the board E2Es this builds the scrum layer on;tests/e2e/board-projection.spec.ts(3.1.7) — the projection E2E precedenttests/helpers/db.ts— real-Postgres truncation; the fixture pattern for setting an active sprint + points directly (the lifecycle UI is Story 4.4)- Story 4.5.2 (projection) + 4.5.3 (header/page) — the units under test; Stories 3.5 / 4.7 — the test stories this defers the at-scale combined journey to
motir-core/CLAUDE.md— test conventions (real Postgres, no mocks, singlegetSessionmock)