Public Access
docs: Sprint 14 — Vitest for useOnboarding (Q4) across all 6 running docs
Sprint 14 (commit28f3212) 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 bug1562929(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.
This commit is contained in:
@@ -22,7 +22,8 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
- **Batch G:** Sprint 11 (one `git pull`, `docker compose up -d --build frontend` — frontend-only, no migration, no backend rebuild).
|
||||
- **Batch H:** Sprint 12 (one `git pull`, `docker compose up -d --build backend frontend` — backend has the new `recipe_search.py` router, frontend has the new toggle).
|
||||
- **Batch I:** Sprint 13 (one `git pull`, `docker compose up -d --build backend frontend` — backend has the new `llm_plan.py` router, frontend has the new prompt modal).
|
||||
4. **Open issues** in `.agent/plan.md` (the "Phase R1-R3" section is a prior plan; the **Sprint 13 active-sprint** section is the current state) and in `.agent/context.md` (decisions + open Qs for the current sprint).
|
||||
- **Batch J:** Sprint 14 (one `git pull`, `npm install` in `frontend/`, `npm test` to confirm 7/7, then `docker compose up -d --build frontend` — no backend change, no migration; the 5 new devDeps land on `npm install`).
|
||||
4. **Open issues** in `.agent/plan.md` (the "Phase R1-R3" section is a prior plan; the **Sprint 14 active-sprint** section is the current state) and in `.agent/context.md` (decisions + open Qs for the current sprint).
|
||||
5. **Do not** touch the pre-existing WIP files: `backend/app/api/recipes.py`, `backend/app/schemas/recipe.py`, `nginx/nginx.conf` (untouched since before this work; user's to manage).
|
||||
6. **When you commit,** use the `fix(ui):`, `feat(ui):`, `refactor(frontend):`, `docs(review):` Conventional Commit style. Force-add new files in `frontend/src/lib/` (the `.gitignore` line 17 `lib/` is a pre-existing bug that catches it).
|
||||
|
||||
@@ -30,6 +31,7 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
|
||||
- Sprints 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8: code committed and build green. Sprint 1 deployed. Sprints 2-8 awaiting user deploy.
|
||||
- The §Future backlog is now empty: F1 (onboarding) shipped as Sprint 9; the dead "Generate Meal Plan" CTA shipped as Sprint 11; F8 (Spoonacular) shipped as Sprint 12; F9-lite shipped as Sprint 13. All four are deployment-pending. F9-full (local Ollama model pull) is the only remaining §Future item — opt-in based on cloud-billing feedback.
|
||||
- **Sprint 14 (Vitest for `useOnboarding`, Q4) code complete on 2026-06-05.** 7/7 tests green in ~25 ms, `npm run build` green, no runtime dep change. Awaiting commit + push. Closes the open Q4 from Sprint 9.
|
||||
- Pre-existing repo issues: 1 failing test (`test_filter_blocks_by_cost` — verified pre-Sprint 8), `.gitignore` `lib/` bug, no CI. Documented.
|
||||
|
||||
---
|
||||
@@ -131,6 +133,18 @@ If you are a new agent continuing this work, do this **in order**:
|
||||
|
||||
**Tracking docs:** `Review/sprint13-verification.md` (deploy + 3-step browser smoke + 4 API curls + a11y check + 6-risk table), `Review/ui-nielsen-audit.md` Sprint 13 status block, `fix-ui-audit.md` T7.1–T7.5, this file, `docs/HANDOFF.md` Sprint 13 section.
|
||||
|
||||
### Sprint 14 — Vitest for `useOnboarding` (Q4) (user-driven)
|
||||
|
||||
**Status: CODE COMPLETE on 2026-06-05. 7/7 tests green in ~25 ms. `npm run build` green. Awaiting user commit + push.** No backend change, no migration, no runtime dep change (5 new devDeps only).
|
||||
|
||||
**Root cause (one-liner):** Sprint 9 (F1 Onboarding Tour) shipped a hand-rolled ~420-line component; the bug `1562929` shipped a post-deploy fix the same day (`onComplete` was wired to `useOnboarding().reset()` — the inverse op). Q4 (open question from Sprint 9) was "add Vitest to lock `useOnboarding` state transitions." Sprint 14 lifts the "no new npm deps" rule for testing-only and locks the bug class at `npm test` time.
|
||||
|
||||
**Scope (5 boxes):** 4 new devDeps (`vitest@^1.6.0`, `happy-dom@^14.7.0`, `@testing-library/react@^14.2.0`, `@testing-library/jest-dom@^6.4.0`) + 1 tsc dep (`@types/node@^20`) + 2 new scripts (`test`, `test:watch`) + 2 new config files (`vitest.config.ts`, `vitest-setup.ts`) + 1 new test file (`OnboardingTour.test.tsx`, 7 cases). **No backend change. No migration. No runtime dep change. No pre-existing WIP files touched.**
|
||||
|
||||
**Case 7 is the load-bearing test:** Sprint 9's bug was at the App.tsx call site, not inside `useOnboarding`. Cases 1-6 lock the hook contract; Case 7 is a static check on `App.tsx` that uses `node:fs/promises` to read the source as a string, runs two regex matches to capture the arrow bodies of `onComplete={...}` and `onReset={...}`, and asserts each body calls the right `onboarding.*` method. Verified: flipping `markComplete` → `reset` in `App.tsx` makes Case 7 fail.
|
||||
|
||||
**Tracking docs:** `Review/sprint14-verification.md` (deploy + test commands + 5-risk table + open Q1), `Review/ui-nielsen-audit.md` Sprint 14 status block, `fix-ui-audit.md` T7.1–T7.5, this file, `docs/HANDOFF.md` Sprint 14 section.
|
||||
|
||||
### Sprint 7 — Fix webui "empty meal plan" (date-semantics mismatch)
|
||||
|
||||
**Status: COMMITTED `09c7525` on 2026-06-05. Build green.** Awaiting user to `git pull` + run the SQL fix + rebuild.
|
||||
@@ -408,4 +422,4 @@ cd frontend && npm run build
|
||||
|
||||
Trust the build output. Trust the smoke checklist. Don't trust the deployment host's UI until the user confirms. The verification model is "I shipped, you verified, you reported, I fixed" — the agent in this role never sees the live UI directly.
|
||||
|
||||
**Last updated: 2026-06-05** — Sprint 1 deployed; Sprints 2-6 awaiting user deploy; **Sprint 7 (`09c7525`), Sprint 8 (`efd1fc6`), Sprint 9 (F1 Onboarding Tour) + post-deploy fix (`1562929`), Sprint 10 (Deny Forever on Recipes), Sprint 11 (Wire the dead "Generate Meal Plan" CTA), Sprint 12 (F8 Spoonacular search), and Sprint 13 (F9-lite Ollama Cloud plan synthesis) committed on 2026-06-05, awaiting user deploy**. See the "How to take over" and "Pending user deploy" sections at the top of this file.
|
||||
**Last updated: 2026-06-05** — Sprint 1 deployed; Sprints 2-6 awaiting user deploy; **Sprint 7 (`09c7525`), Sprint 8 (`efd1fc6`), Sprint 9 (F1 Onboarding Tour) + post-deploy fix (`1562929`), Sprint 10 (Deny Forever on Recipes), Sprint 11 (Wire the dead "Generate Meal Plan" CTA), Sprint 12 (F8 Spoonacular search), and Sprint 13 (F9-lite Ollama Cloud plan synthesis) committed on 2026-06-05, awaiting user deploy; Sprint 14 (Vitest for `useOnboarding`) code complete, 7/7 tests green, awaiting commit + push**. See the "How to take over" and "Pending user deploy" sections at the top of this file.
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
```bash
|
||||
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.
|
||||
@@ -139,6 +139,13 @@ The app looks polished on the surface (Tailwind palette, clean cards, working to
|
||||
> - **Verification log:** `Review/sprint13-verification.md` (deploy + 3-step browser smoke + 4 API curls + a11y check + 6-risk table). Deploy is `git pull` + `docker compose up -d --build backend frontend` (no migration, no new dependencies).
|
||||
> - **No new dependencies. No migration. Admin path unchanged.**
|
||||
>
|
||||
> **Sprint 14 status (in progress 2026-06-05, code complete, awaiting commit + push):** Vitest for `useOnboarding` (Q4) — locks the S9 bug class with 7 unit tests. 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 at `npm test` time.
|
||||
> - **T7.1** 4 new devDeps: `vitest@^1.6.0`, `happy-dom@^14.7.0`, `@testing-library/react@^14.2.0`, `@testing-library/jest-dom@^6.4.0` + `@types/node@^20` (tsc). Lifts the "no new npm deps" rule for testing-only. Runtime bundle unchanged.
|
||||
> - **T7.2** `frontend/vitest.config.ts` (NEW) — happy-dom env, setup file, `src/**/*.test.{ts,tsx}` glob. `frontend/vitest-setup.ts` (NEW) — `@testing-library/jest-dom/vitest` matchers. `package.json` scripts: `test` (vitest run, no watch) + `test:watch`.
|
||||
> - **T7.3** `frontend/src/components/OnboardingTour.test.tsx` (NEW) — 7 cases: clean init, persisted init, `markComplete` (state → true, localStorage **stays** at `'1'`), `reset` (localStorage cleared + state → false), `show` mirror, localStorage throw silently swallowed, App.tsx wiring static check (catches the original S9 bug `onComplete → reset` at the call site). 7/7 pass in ~25 ms.
|
||||
> - **Verification log:** `Review/sprint14-verification.md`. `npm run build` still green (bundle 503.82 kB unchanged). No migration. No backend change. Deploy is `git pull` + `npm install` (frontend) + `docker compose up -d --build frontend`.
|
||||
> - **No new runtime dependencies. No migration. Admin path unchanged. Component-level tests for `<OnboardingTour/>` (focus, arrow keys, dialog a11y) deferred to a future sprint.**
|
||||
>
|
||||
> **Sprint 6 status (commit `8ad4ef6`, awaiting deploy):** Two §Future items, both with design decisions captured in the commit message.
|
||||
> - **F3** Bulk 'add checked to pantry' on ShoppingList. Backend `POST /api/pantry/bulk` accepts `{items: HomePantryCreate[]}` and returns per-item status (`added` / `updated` / `skipped`) with totals. Per-item failure model: unknown ingredient → `skipped` with reason, not a 4xx. Frontend ShoppingList gains a primary `Add N to pantry` button next to the existing Reset button; toast reports `added X, updated Y, skipped Z`; only the items that actually landed are removed from the checked Set. **Scope decision:** ShoppingList only (the checked Set was the natural substrate; Pantry would need new multi-select UI).
|
||||
> - **F4** Plan the whole week on Dashboard. Backend `POST /api/meals/{id}/fill-empty-slots` with body `{meal_types: [str, ...]}` returns `FillEmptySlotsResult { filled: [{day, meal_type, item}], failed: [{day, meal_type, reason}] }`. Iterates day 1..7 in order; skips already-occupied slots; picks a recipe (prefer un-used, fall back to any) and inserts as `pending`. Per-slot failure model — never aborts mid-batch. Frontend Dashboard gets a primary `Plan the week` button (next to the Sprint 5 week-nav control) with a dropdown: `Dinners only` / `All meals`. Toast reports partial-success precisely: `Planned 12 of 21 meal slots — 9 failed (e.g. <reason>)`.
|
||||
|
||||
Reference in New Issue
Block a user