Files
Meal-Planner/Review/sprint14-verification.md
T
admin af4ec793c7 docs: Sprint 14 — Vitest for useOnboarding (Q4) across all 6 running docs
Sprint 14 (commit 28f3212) adds Vitest + happy-dom +
@testing-library/react + @testing-library/jest-dom as
devDeps and locks the useOnboarding state-transition
contract with 7 unit tests in 25 ms. Lifts the 'no new
npm deps' rule for testing-only. Runtime bundle unchanged
(503.82 kB). No pre-existing WIP files touched.

Sprint 9's bug 1562929 (onComplete wired to .reset, the
inverse op) shipped a post-deploy fix the same day.
Sprint 14 prevents recurrence at npm test time.

This commit updates the 6 running docs that track sprints:

- .agent/plan.md — header changed to 'Active sprint: Sprint
  14'; Sprint 14 section (S14.1-S14.4 + Done when + Out of
  scope) added after the Sprint 13 section.
- .agent/context.md — Sprint 14 decisions (D1-D7), open Q1,
  and file:line references added.
- Review/sprint14-verification.md — NEW: deploy + 7-case
  test table + verification commands + Case 7 S9-bug-catch
  proof + 5-risk table + open Q1 (component-level tests).
- Review/ui-nielsen-audit.md — Sprint 14 status block
  (T7.1-T7.3) added after the Sprint 13 block.
- fix-ui-audit.md — Sprint 14 section (T7.1-T7.5) added
  after the Sprint 13 section.
- Review/handoff-ui-audit.md — Batch J line in deploy
  list, Sprint 14 section after Sprint 13, TL;DR Sprint
  14 line, Last-updated footer updated. (Did NOT replace
  the Sprint 7/8/TL;DR/environment-quirks/active-risks
  content that was at the bottom of the file — that
  material is preserved unchanged.)
- docs/HANDOFF.md — Sprint 14 section added after Sprint
  13, Last-updated footer updated.

All 6 docs now reflect Sprint 14. §Future backlog
remaining: F9-full (local Ollama model pull on the host).
Q4 (Vitest) is now closed. Sprint 14 is the smallest
sprint in the cycle (devDeps + 1 test file + 2 config
files + 2 scripts) and the first that adds a test
infrastructure layer.
2026-06-05 17:30:00 -07:00

4.9 KiB

Sprint 14 Verification — Vitest for useOnboarding (Q4)

Date: 2026-06-05. Owner: this agent. Status: code complete, 7/7 tests green, npm run build green, awaiting commit + push.

What Sprint 14 does

Adds Vitest + @testing-library/react + happy-dom to the frontend devDeps and locks the useOnboarding state-transition contract with 7 unit tests. The S9 bug class (wiring onComplete to a call that flips isComplete to false, e.g. onboarding.reset()) is now caught at npm test time. Sprint 9 (F1 Onboarding Tour) shipped a hand-rolled ~420-line component; the bug 1562929 shipped a post-deploy fix the same day. Sprint 14 prevents recurrence.

Why this sprint, why this scope

  • Q4 (open question from Sprint 9): "Add Vitest to lock useOnboarding state transitions." Cost: ~1 hr. Value: prevents the S9 bug class. Decision: lift the "no new npm deps" rule for testing-only (devDeps).
  • Hook-only, not component-level. The S9 bug was at the App.tsx call-site. Sprint 14 includes one integration test (Case 7) that statically reads App.tsx and asserts the wiring. Component-level tests (focus, arrow keys, dialog a11y) are a future sprint.

Files added

  • frontend/vitest.config.ts — happy-dom env, setup file, src/**/*.test.{ts,tsx} glob.
  • frontend/vitest-setup.ts@testing-library/jest-dom/vitest matchers.
  • frontend/src/components/OnboardingTour.test.tsx — 7 cases.

Files modified

  • frontend/package.json — 4 new devDeps (vitest, happy-dom, @testing-library/react, @testing-library/jest-dom) + 1 devDep for tsc (@types/node) + 2 scripts (test, test:watch).
  • .agent/plan.md — S14 sections (S14.1-S14.4 + Done when + Out of scope).
  • .agent/context.md — S14 decisions (D1-D7), open question (Q1), file:line references.

Test cases (S14.3)

# Case What it locks
1 clean init isComplete === false when localStorage is empty
2 persisted init isComplete === true when localStorage.getItem(KEY) === '1'
3 markComplete state → true, localStorage stays at '1' (locks one direction of the S9 bug)
4 reset localStorage cleared, state → false
5 show identical to reset (intentional mirror)
6 localStorage throw on read silently swallowed, isComplete === false, no crash
7 App.tsx wiring static check: onComplete calls markComplete, onReset calls reset; neither inverts (locks the original S9 bug at the call site)

Verification commands

ssh docker-willester
cd /home/peter/MealPlanner/frontend

# 1. install (already done on host; rerun if pulling to a fresh checkout)
npm install

# 2. run tests
npm test
# → 7 passed in ~25 ms

# 3. build (still green; vitest is devDeps only)
npm run build
# → tsc 0 errors, vite built in ~2.6 s, bundle 503.82 kB unchanged

# 4. prove Case 7 catches the bug (manual)
sed -i 's|onboarding.markComplete()|onboarding.reset()|' src/App.tsx
npm test
# → 1 failed (Case 7: onCompleteBody does not match /markComplete/)
sed -i 's|onboarding.reset()|onboarding.markComplete()|' src/App.tsx  # restore
npm test
# → 7 passed

Deploy

No backend change. No migration. No new runtime dep. The 5 new devDeps land on npm install on the host.

ssh docker-willester
cd /home/peter/MealPlanner
git pull
cd frontend && npm install && npm test   # confirm 7/7 in CI
cd .. && docker compose up -d --build frontend

If the user wants Vitest in CI (currently not wired), that is a follow-up — outside Sprint 14 scope.

What Sprint 14 does NOT do

  • No component-level tests for <OnboardingTour/>. Focus, arrow keys, dialog a11y, portal positioning. Future sprint. Would add @testing-library/user-event for keyboard simulation.
  • No backend tests. Venv on docker-willester is broken (Nix symlinks to /run/current-system/sw/bin/python). Frontend-only sprint.
  • No CI integration. Tests are local-only. Wiring them into a CI runner is a follow-up.

Risk table

Risk Mitigation Status
Vitest conflicts with Vite 5 config vitest.config.ts uses defineConfig from vitest/config which extends Vite's; tested, no conflict Resolved
node:* imports in tests break tsc Added @types/node as devDep Resolved
Tests slow CI 7 cases run in 25 ms; not a concern N/A
Devs forget to run npm test before commit Follow-up: pre-commit hook or CI; not in Sprint 14 Open
Future refactor adds a hook dependency that breaks Case 7's regex Case 7 uses a single-shot regex match; if App.tsx gains a markComplete call in unrelated code (e.g. button), the regex still works because the onComplete arrow body is the captured group Resolved (verified)

Open question for follow-up

Q1 — Should Sprint 15 add component-level tests for <OnboardingTour/> (focus, arrow keys, dialog a11y)? Default: yes, future sprint. Adds @testing-library/user-event. ~1.5 hr.