From 60745b32811426bd22d3ad7d2e0c7e70708370b2 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Tue, 9 Jun 2026 12:10:31 -0400 Subject: [PATCH] refactor(04-01): move API list test stubs into tests/ mirror dir to match convention The two Wave-0 RED stubs (lists.test.ts, listEmitter.test.ts) were co-located in src/ but all existing API tests live in apps/api/tests/. Move them to tests/routes/ and tests/lib/, add explicit vitest imports to match the tests/ convention, and update path references in downstream plans 04-02..04-06. PWA tests keep co-location (that IS the PWA convention). --- .../phases/04-shared-lists-live-sync/04-01-PLAN.md | 14 +++++++------- .../04-shared-lists-live-sync/04-01-SUMMARY.md | 4 ++-- .../phases/04-shared-lists-live-sync/04-02-PLAN.md | 12 ++++++------ .../phases/04-shared-lists-live-sync/04-03-PLAN.md | 10 +++++----- .../phases/04-shared-lists-live-sync/04-04-PLAN.md | 10 +++++----- .../phases/04-shared-lists-live-sync/04-05-PLAN.md | 10 +++++----- .../phases/04-shared-lists-live-sync/04-06-PLAN.md | 10 +++++----- .../04-shared-lists-live-sync/04-RESEARCH.md | 4 ++-- .../04-shared-lists-live-sync/04-VALIDATION.md | 4 ++-- apps/api/{src => tests}/lib/listEmitter.test.ts | 2 ++ apps/api/{src => tests}/routes/lists.test.ts | 2 ++ 11 files changed, 43 insertions(+), 39 deletions(-) rename apps/api/{src => tests}/lib/listEmitter.test.ts (95%) rename apps/api/{src => tests}/routes/lists.test.ts (98%) diff --git a/.planning/phases/04-shared-lists-live-sync/04-01-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-01-PLAN.md index de2b177..6f36701 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-01-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-01-PLAN.md @@ -11,8 +11,8 @@ files_modified: - apps/api/src/db/migrations/0002_lists_schema.sql - apps/api/test/setup.ts - apps/api/vitest.config.ts - - apps/api/src/routes/lists.test.ts - - apps/api/src/lib/listEmitter.test.ts + - apps/api/tests/routes/lists.test.ts + - apps/api/tests/lib/listEmitter.test.ts - apps/pwa/src/hooks/useListSSE.test.ts - apps/pwa/src/routes/ListDetail.test.tsx - apps/pwa/src/App.tsx @@ -42,7 +42,7 @@ must_haves: - path: "apps/pwa/src/routes/ListsIndex.tsx" provides: "Lists surface with empty state" min_lines: 20 - - path: "apps/api/src/routes/lists.test.ts" + - path: "apps/api/tests/routes/lists.test.ts" provides: "RED test stubs for LIST-01/02/03/04 API behavior" contains: "describe" key_links: @@ -109,7 +109,7 @@ Output: New deps installed; three tables migrated; API vitest harness + 4 RED st Task 2: Install new dependencies + scaffold API test harness with Wave-0 RED stubs - apps/pwa/package.json, apps/api/package.json, apps/api/test/setup.ts, apps/api/vitest.config.ts, apps/api/src/routes/lists.test.ts, apps/api/src/lib/listEmitter.test.ts, apps/pwa/src/hooks/useListSSE.test.ts, apps/pwa/src/routes/ListDetail.test.tsx + apps/pwa/package.json, apps/api/package.json, apps/api/test/setup.ts, apps/api/vitest.config.ts, apps/api/tests/routes/lists.test.ts, apps/api/tests/lib/listEmitter.test.ts, apps/pwa/src/hooks/useListSSE.test.ts, apps/pwa/src/routes/ListDetail.test.tsx - apps/api/vitest.config.ts - apps/api/src/db/client.ts @@ -123,8 +123,8 @@ Output: New deps installed; three tables migrated; API vitest harness + 4 RED st Scaffold the API test harness: the API currently has zero test files. Create `apps/api/test/setup.ts` and reference it from `apps/api/vitest.config.ts` (`test.setupFiles`). The setup file must establish how DB-backed route tests connect — point at the local MariaDB via the existing `apps/api/src/db/client.ts` pool (DB_HOST/DB_NAME from env), and provide a per-test cleanup (truncate lists/list_items/list_shares between tests). Pure-logic tests (listEmitter, fractional rank) do NOT need the DB. Create the four Wave-0 RED stub test files listed in 04-VALIDATION.md, each with `describe`/`it.todo` or `it(... )` blocks that compile and FAIL (red) rather than error on import — they import the not-yet-existing modules behind a guard or use `it.todo` placeholders that downstream plans convert to real assertions: - - apps/api/src/routes/lists.test.ts — LIST-01/02/03/04 API behavior stubs - - apps/api/src/lib/listEmitter.test.ts — scoped fan-out correctness (D-04) stubs + - apps/api/tests/routes/lists.test.ts — LIST-01/02/03/04 API behavior stubs + - apps/api/tests/lib/listEmitter.test.ts — scoped fan-out correctness (D-04) stubs - apps/pwa/src/hooks/useListSSE.test.ts — D-11 bounded backoff (mock EventSource) stubs - apps/pwa/src/routes/ListDetail.test.tsx — D-07 optimistic update + rollback stubs @@ -248,7 +248,7 @@ Output: New deps installed; three tables migrated; API vitest harness + 4 RED st - Tables: `lists`, `list_shares`, `list_items` (apps/api/src/db/schema.ts) - Migration: `apps/api/src/db/migrations/0002_lists_schema.sql` (+ journal/snapshot) - API test harness: `apps/api/test/setup.ts`; setupFiles wiring in `apps/api/vitest.config.ts` -- RED stub tests: `apps/api/src/routes/lists.test.ts`, `apps/api/src/lib/listEmitter.test.ts`, `apps/pwa/src/hooks/useListSSE.test.ts`, `apps/pwa/src/routes/ListDetail.test.tsx` +- RED stub tests: `apps/api/tests/routes/lists.test.ts`, `apps/api/tests/lib/listEmitter.test.ts`, `apps/pwa/src/hooks/useListSSE.test.ts`, `apps/pwa/src/routes/ListDetail.test.tsx` - Components: `BottomTabBar` (apps/pwa/src/components/BottomTabBar.tsx), `ListsIndex` (apps/pwa/src/routes/ListsIndex.tsx), temporary ListDetail placeholder route element - Store: `useListsStore` (apps/pwa/src/store/listsStore.ts) with activeTab/createListSheetOpen - App.tsx now exports a BrowserRouter-wrapped App + AppShell diff --git a/.planning/phases/04-shared-lists-live-sync/04-01-SUMMARY.md b/.planning/phases/04-shared-lists-live-sync/04-01-SUMMARY.md index 63cc4ff..ec538a7 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-01-SUMMARY.md +++ b/.planning/phases/04-shared-lists-live-sync/04-01-SUMMARY.md @@ -38,8 +38,8 @@ key_files: - apps/pwa/src/store/listsStore.ts - apps/pwa/src/api/listsClient.ts (fetchLists + List/ListItem types) - apps/api/test/setup.ts - - apps/api/src/routes/lists.test.ts - - apps/api/src/lib/listEmitter.test.ts + - apps/api/tests/routes/lists.test.ts + - apps/api/tests/lib/listEmitter.test.ts - apps/pwa/src/hooks/useListSSE.test.ts - apps/pwa/src/routes/ListDetail.test.tsx - apps/api/src/db/migrations/0002_lists_schema.sql diff --git a/.planning/phases/04-shared-lists-live-sync/04-02-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-02-PLAN.md index d01dc74..8bbde27 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-02-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-02-PLAN.md @@ -6,7 +6,7 @@ wave: 2 depends_on: ["04-01"] files_modified: - apps/api/src/lib/listEmitter.ts - - apps/api/src/lib/listEmitter.test.ts + - apps/api/tests/lib/listEmitter.test.ts - apps/api/src/lib/listAccess.ts - apps/api/src/lib/listAccess.test.ts autonomous: true @@ -26,7 +26,7 @@ must_haves: - path: "apps/api/src/lib/listAccess.ts" provides: "getAccessibleListIds(userId) access-scope query" exports: ["getAccessibleListIds"] - - path: "apps/api/src/lib/listEmitter.test.ts" + - path: "apps/api/tests/lib/listEmitter.test.ts" provides: "scoped fan-out correctness tests (D-04)" contains: "describe" key_links: @@ -65,11 +65,11 @@ Output: `publishListEvent`/`subscribeListEvents` (in-memory EventEmitter singlet Scoped in-memory list event fan-out + access-scope query (D-04) - apps/api/src/lib/listEmitter.ts, apps/api/src/lib/listEmitter.test.ts, + apps/api/src/lib/listEmitter.ts, apps/api/tests/lib/listEmitter.test.ts, apps/api/src/lib/listAccess.ts, apps/api/src/lib/listAccess.test.ts - - apps/api/src/lib/listEmitter.test.ts (RED stub from Plan 01 — convert to real assertions) + - apps/api/tests/lib/listEmitter.test.ts (RED stub from Plan 01 — convert to real assertions) - apps/api/src/db/schema.ts (lists, listShares tables created in Plan 01) - apps/api/src/routes/events.ts lines 1-110 (db query + drizzle and/or/eq conventions) - .planning/phases/04-shared-lists-live-sync/04-RESEARCH.md Finding 1 + Finding 3 (verbatim patterns) @@ -116,7 +116,7 @@ Output: `publishListEvent`/`subscribeListEvents` (in-memory EventEmitter singlet -pnpm --filter @familysync/api exec vitest run src/lib/listEmitter.test.ts src/lib/listAccess.test.ts +pnpm --filter @familysync/api exec vitest run tests/lib/listEmitter.test.ts src/lib/listAccess.test.ts - Test 2 (cross-list isolation) and Test 7 (private list excluded) MUST be present and green. @@ -131,7 +131,7 @@ Output: `publishListEvent`/`subscribeListEvents` (in-memory EventEmitter singlet **Symbols/files this plan creates (exclude from drift verification):** - `apps/api/src/lib/listEmitter.ts` exporting `publishListEvent(listId, event)`, `subscribeListEvents(listId, handler): () => void`, type `ListEvent` - `apps/api/src/lib/listAccess.ts` exporting `getAccessibleListIds(userId): Promise` -- Tests: `apps/api/src/lib/listEmitter.test.ts`, `apps/api/src/lib/listAccess.test.ts` +- Tests: `apps/api/tests/lib/listEmitter.test.ts`, `apps/api/src/lib/listAccess.test.ts` diff --git a/.planning/phases/04-shared-lists-live-sync/04-03-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-03-PLAN.md index e8de4cb..cf175de 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-03-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-03-PLAN.md @@ -6,7 +6,7 @@ wave: 2 depends_on: ["04-01"] files_modified: - apps/api/src/routes/lists.ts - - apps/api/src/routes/lists.test.ts + - apps/api/tests/routes/lists.test.ts - apps/api/src/index.ts - apps/pwa/src/api/listsClient.ts - apps/pwa/src/routes/ListsIndex.tsx @@ -80,10 +80,10 @@ Output: listsRouter mounted at /api/lists; ListsIndex wired to real data; Create Task 1: Lists router — POST/GET/PATCH/DELETE /api/lists with scoped access (LIST-01, D-01/D-02/D-04/D-06) - apps/api/src/routes/lists.ts, apps/api/src/routes/lists.test.ts, apps/api/src/index.ts + apps/api/src/routes/lists.ts, apps/api/tests/routes/lists.test.ts, apps/api/src/index.ts - apps/api/src/routes/events.ts (full — resolveUserId, zod schemas, handler/try-catch/401 conventions) - - apps/api/src/routes/lists.test.ts (RED stub from Plan 01) + - apps/api/tests/routes/lists.test.ts (RED stub from Plan 01) - apps/api/src/index.ts (route mount order) - apps/api/src/auth/user.ts (upsertUser, deriveDisplayName signatures) - apps/api/src/db/schema.ts (lists, listShares, listItems, users) @@ -107,7 +107,7 @@ Output: listsRouter mounted at /api/lists; ListsIndex wired to real data; Create Mount in index.ts: `import { listsRouter }` and `app.route('/api/lists', listsRouter)` after the sseRouter mount (so it sits behind the OIDC/dev-bypass guard). Do NOT add fan-out emit calls here yet — Plan 06 adds publishListEvent triggers once the SSE endpoint exists (leave a commented seam, note it in SUMMARY). NOTE: per-field item PATCH and item endpoints are Plan 04; this plan is lists only. - pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts && grep -q "app.route('/api/lists'" apps/api/src/index.ts && pnpm --filter @familysync/api typecheck + pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts && grep -q "app.route('/api/lists'" apps/api/src/index.ts && pnpm --filter @familysync/api typecheck - lists.test.ts: all create/get/delete/patch/scope tests green, including the D-04 "private list of another member is NOT returned by GET /api/lists" assertion. @@ -176,7 +176,7 @@ Output: listsRouter mounted at /api/lists; ListsIndex wired to real data; Create -pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit +pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit - `playwright-cli`: create + delete a list end to end. - D-04 negative test green. diff --git a/.planning/phases/04-shared-lists-live-sync/04-04-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-04-PLAN.md index 49f1f61..07521f4 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-04-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-04-PLAN.md @@ -6,7 +6,7 @@ wave: 3 depends_on: ["04-03"] files_modified: - apps/api/src/routes/lists.ts - - apps/api/src/routes/lists.test.ts + - apps/api/tests/routes/lists.test.ts - apps/api/src/lib/rank.ts - apps/api/src/lib/rank.test.ts - apps/pwa/src/api/listsClient.ts @@ -77,10 +77,10 @@ Output: item endpoints on listsRouter (POST items, per-field PATCH, DELETE); ran Task 1: Item endpoints + fractional-rank assignment (LIST-02, D-05/D-08/D-09) - apps/api/src/routes/lists.ts, apps/api/src/routes/lists.test.ts, apps/api/src/lib/rank.ts, apps/api/src/lib/rank.test.ts + apps/api/src/routes/lists.ts, apps/api/tests/routes/lists.test.ts, apps/api/src/lib/rank.ts, apps/api/src/lib/rank.test.ts - apps/api/src/routes/lists.ts (listsRouter from Plan 03 — extend; access-check pattern) - - apps/api/src/routes/lists.test.ts (item stubs) + - apps/api/tests/routes/lists.test.ts (item stubs) - apps/api/src/db/schema.ts (listItems) - .planning/phases/04-shared-lists-live-sync/04-RESEARCH.md Finding 2 (fractional-indexing API), Finding 6 (per-field PATCH zod), §"Open Questions" item 2 (uncheck rank) - .planning/phases/04-shared-lists-live-sync/04-PATTERNS.md §"apps/api/src/routes/lists.ts" (zod patchItemSchema, ownership verification) @@ -105,7 +105,7 @@ Output: item endpoints on listsRouter (POST items, per-field PATCH, DELETE); ran Note the route paths: items-by-list use /:id/items (nested under lists); single-item mutations use /list-items/:itemId at the listsRouter root (matches RESEARCH architecture diagram). Mount accordingly so both resolve under /api. Do NOT add publishListEvent here — Plan 06 inserts fan-out triggers (leave a clearly commented seam after each successful write). - pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts src/lib/rank.test.ts && pnpm --filter @familysync/api typecheck + pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts src/lib/rank.test.ts && pnpm --filter @familysync/api typecheck - rank.ts tests green; ordering stable. @@ -172,7 +172,7 @@ Output: item endpoints on listsRouter (POST items, per-field PATCH, DELETE); ran -pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts src/lib/rank.test.ts && pnpm --filter @familysync/pwa exec vitest run src/routes/ListDetail.test.tsx +pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts src/lib/rank.test.ts && pnpm --filter @familysync/pwa exec vitest run src/routes/ListDetail.test.tsx - `playwright-cli`: add / check / delete items in a real browser. diff --git a/.planning/phases/04-shared-lists-live-sync/04-05-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-05-PLAN.md index 9856440..adc98e2 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-05-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-05-PLAN.md @@ -9,7 +9,7 @@ files_modified: - apps/pwa/src/components/ItemRow.tsx - apps/pwa/src/api/listsClient.ts - apps/api/src/lib/rank.test.ts - - apps/api/src/routes/lists.test.ts + - apps/api/tests/routes/lists.test.ts autonomous: true requirements: [LIST-03] user_setup: [] @@ -97,10 +97,10 @@ Output: dnd-kit DndContext/SortableContext in ListDetail; sortable ItemRow with Task 2: Strengthen server-side reorder ordering tests (LIST-03, D-13) - apps/api/src/lib/rank.test.ts, apps/api/src/routes/lists.test.ts + apps/api/src/lib/rank.test.ts, apps/api/tests/routes/lists.test.ts - apps/api/src/lib/rank.test.ts (from Plan 04) - - apps/api/src/routes/lists.test.ts (PATCH position coverage) + - apps/api/tests/routes/lists.test.ts (PATCH position coverage) - .planning/phases/04-shared-lists-live-sync/04-VALIDATION.md (LIST-03 row: "PATCH new rank produces correct fractional order") - .planning/phases/04-shared-lists-live-sync/04-RESEARCH.md §"Common Pitfalls" Pitfall 2 (precision) @@ -108,7 +108,7 @@ Output: dnd-kit DndContext/SortableContext in ListDetail; sortable ItemRow with Add server-side tests proving reorder correctness: (a) repeated mid-point inserts via rankBetween produce strictly increasing distinct strings over many iterations (precision does not collapse — Pitfall 2); (b) PATCH /api/list-items/:id { position } updates only rank and a subsequent GET returns items in the new ASC order; (c) moving an item between two neighbors yields a rank strictly between theirs. These align the LIST-03 row in 04-VALIDATION.md to a green automated check. No production behavior change — Plan 04 already implements the PATCH position path. - pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts src/routes/lists.test.ts + pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts tests/routes/lists.test.ts - LIST-03 ordering test ("PATCH new rank produces correct fractional order") is present and green. @@ -136,7 +136,7 @@ Output: dnd-kit DndContext/SortableContext in ListDetail; sortable ItemRow with -pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts src/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit +pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts tests/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit - `playwright-cli`: drag-reorder persists across reload. diff --git a/.planning/phases/04-shared-lists-live-sync/04-06-PLAN.md b/.planning/phases/04-shared-lists-live-sync/04-06-PLAN.md index 13789ef..526b69d 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-06-PLAN.md +++ b/.planning/phases/04-shared-lists-live-sync/04-06-PLAN.md @@ -7,7 +7,7 @@ depends_on: ["04-02", "04-04", "04-05"] files_modified: - apps/api/src/routes/sse.ts - apps/api/src/routes/lists.ts - - apps/api/src/routes/lists.test.ts + - apps/api/tests/routes/lists.test.ts - apps/pwa/src/hooks/useListSSE.ts - apps/pwa/src/hooks/useListSSE.test.ts - apps/pwa/src/components/LiveSyncIndicator.tsx @@ -76,13 +76,13 @@ Output: /api/sse/lists endpoint; publishListEvent triggers in lists.ts; useListS Task 1: Scoped /api/sse/lists endpoint + fan-out triggers on every write (LIST-04, D-04/D-10) - apps/api/src/routes/sse.ts, apps/api/src/routes/lists.ts, apps/api/src/routes/lists.test.ts + apps/api/src/routes/sse.ts, apps/api/src/routes/lists.ts, apps/api/tests/routes/lists.test.ts - apps/api/src/routes/sse.ts (existing /heartbeat streamSSE pattern — extend) - apps/api/src/routes/lists.ts (item/list write handlers from Plans 03–04 — add emit seams) - apps/api/src/lib/listEmitter.ts (publishListEvent, subscribeListEvents — Plan 02) - apps/api/src/lib/listAccess.ts (getAccessibleListIds — Plan 02) - - apps/api/src/routes/lists.test.ts (LIST-04 stub incl. private-list no-leak) + - apps/api/tests/routes/lists.test.ts (LIST-04 stub incl. private-list no-leak) - .planning/phases/04-shared-lists-live-sync/04-PATTERNS.md §"apps/api/src/routes/sse.ts" (the /lists endpoint pattern verbatim) - .planning/phases/04-shared-lists-live-sync/04-RESEARCH.md Finding 1 + Finding 3 @@ -100,7 +100,7 @@ Output: /api/sse/lists endpoint; publishListEvent triggers in lists.ts; useListS Mount: /api/sse/lists is already under /api/sse (sseRouter mounted in index.ts) — no index.ts change needed beyond what exists. Confirm it sits behind the OIDC/dev-bypass guard. - pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts && grep -q "publishListEvent" apps/api/src/routes/lists.ts && grep -q "/lists" apps/api/src/routes/sse.ts && pnpm --filter @familysync/api typecheck + pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts && grep -q "publishListEvent" apps/api/src/routes/lists.ts && grep -q "/lists" apps/api/src/routes/sse.ts && pnpm --filter @familysync/api typecheck - GET /api/sse/lists subscribes only to getAccessibleListIds channels; 401 when unauthenticated. @@ -169,7 +169,7 @@ Output: /api/sse/lists endpoint; publishListEvent triggers in lists.ts; useListS -pnpm --filter @familysync/api exec vitest run src/routes/lists.test.ts && pnpm --filter @familysync/pwa exec vitest run src/hooks/useListSSE.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit +pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts && pnpm --filter @familysync/pwa exec vitest run src/hooks/useListSSE.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit - `playwright-cli` two-context live-update check. - D-04 route-layer no-leak test green. diff --git a/.planning/phases/04-shared-lists-live-sync/04-RESEARCH.md b/.planning/phases/04-shared-lists-live-sync/04-RESEARCH.md index ba8bc1f..bf55778 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-RESEARCH.md +++ b/.planning/phases/04-shared-lists-live-sync/04-RESEARCH.md @@ -1020,8 +1020,8 @@ useMutation({ ### Wave 0 Gaps -- [ ] `apps/api/src/routes/lists.test.ts` — covers LIST-01/02/03/04 API behavior -- [ ] `apps/api/src/lib/listEmitter.test.ts` — covers scoped fan-out correctness (D-04) +- [ ] `apps/api/tests/routes/lists.test.ts` — covers LIST-01/02/03/04 API behavior +- [ ] `apps/api/tests/lib/listEmitter.test.ts` — covers scoped fan-out correctness (D-04) - [ ] `apps/pwa/src/hooks/useListSSE.test.ts` — covers D-11 bounded backoff with mock EventSource - [ ] `apps/pwa/src/routes/ListDetail.test.tsx` — covers optimistic update + rollback (D-07) diff --git a/.planning/phases/04-shared-lists-live-sync/04-VALIDATION.md b/.planning/phases/04-shared-lists-live-sync/04-VALIDATION.md index dac1942..e45ea22 100644 --- a/.planning/phases/04-shared-lists-live-sync/04-VALIDATION.md +++ b/.planning/phases/04-shared-lists-live-sync/04-VALIDATION.md @@ -56,8 +56,8 @@ created: 2026-06-09 ## Wave 0 Requirements -- [ ] `apps/api/src/routes/lists.test.ts` — LIST-01/02/03/04 API behavior -- [ ] `apps/api/src/lib/listEmitter.test.ts` — scoped fan-out correctness (D-04) +- [ ] `apps/api/tests/routes/lists.test.ts` — LIST-01/02/03/04 API behavior +- [ ] `apps/api/tests/lib/listEmitter.test.ts` — scoped fan-out correctness (D-04) - [ ] `apps/pwa/src/hooks/useListSSE.test.ts` — D-11 bounded backoff with mock EventSource - [ ] `apps/pwa/src/routes/ListDetail.test.tsx` — optimistic update + rollback (D-07) diff --git a/apps/api/src/lib/listEmitter.test.ts b/apps/api/tests/lib/listEmitter.test.ts similarity index 95% rename from apps/api/src/lib/listEmitter.test.ts rename to apps/api/tests/lib/listEmitter.test.ts index fb78602..e4ceef2 100644 --- a/apps/api/src/lib/listEmitter.test.ts +++ b/apps/api/tests/lib/listEmitter.test.ts @@ -9,6 +9,8 @@ * Run: pnpm --filter @familysync/api test */ +import { describe, it } from 'vitest' + describe('listEmitter — scoped fan-out correctness (D-04)', () => { it.todo('publishListEvent emits only to subscribers for the matching listId') it.todo('publishListEvent does NOT emit to subscribers for a different listId') diff --git a/apps/api/src/routes/lists.test.ts b/apps/api/tests/routes/lists.test.ts similarity index 98% rename from apps/api/src/routes/lists.test.ts rename to apps/api/tests/routes/lists.test.ts index 27663a4..82f7133 100644 --- a/apps/api/src/routes/lists.test.ts +++ b/apps/api/tests/routes/lists.test.ts @@ -10,6 +10,8 @@ * Run: pnpm --filter @familysync/api test */ +import { describe, it } from 'vitest' + describe('GET /api/lists — LIST-01: returns only accessible lists', () => { it.todo('returns empty array when user has no lists') it.todo('returns lists owned by the current user')