refactor(04): move rank.test.ts into tests/ mirror dir (convention + dist hygiene)

src/lib/rank.test.ts was the last co-located API test. The API tsconfig excludes
tests/ from the build, so all test files belong there; a test in src/ gets compiled
into dist/ and vitest then runs the stale compiled copy (the source of phantom
'22 todo' and dist sourcemap warnings). Moving it to tests/lib/ matches convention
and leaves zero test files in src/, so the production build no longer emits test
artifacts. Updated rank.test.ts path refs in phase-04 plan docs.
This commit is contained in:
Lucas Berger
2026-06-09 13:40:11 -04:00
parent ca9e97879f
commit 690f0b95c0
5 changed files with 20 additions and 20 deletions
@@ -8,7 +8,7 @@ files_modified:
- apps/api/src/routes/lists.ts - apps/api/src/routes/lists.ts
- apps/api/tests/routes/lists.test.ts - apps/api/tests/routes/lists.test.ts
- apps/api/src/lib/rank.ts - apps/api/src/lib/rank.ts
- apps/api/src/lib/rank.test.ts - apps/api/tests/lib/rank.test.ts
- apps/pwa/src/api/listsClient.ts - apps/pwa/src/api/listsClient.ts
- apps/pwa/src/routes/ListDetail.tsx - apps/pwa/src/routes/ListDetail.tsx
- apps/pwa/src/routes/ListDetail.test.tsx - apps/pwa/src/routes/ListDetail.test.tsx
@@ -77,7 +77,7 @@ Output: item endpoints on listsRouter (POST items, per-field PATCH, DELETE); ran
<task type="auto" tdd="true"> <task type="auto" tdd="true">
<name>Task 1: Item endpoints + fractional-rank assignment (LIST-02, D-05/D-08/D-09)</name> <name>Task 1: Item endpoints + fractional-rank assignment (LIST-02, D-05/D-08/D-09)</name>
<files>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</files> <files>apps/api/src/routes/lists.ts, apps/api/tests/routes/lists.test.ts, apps/api/src/lib/rank.ts, apps/api/tests/lib/rank.test.ts</files>
<read_first> <read_first>
- apps/api/src/routes/lists.ts (listsRouter from Plan 03 — extend; access-check pattern) - apps/api/src/routes/lists.ts (listsRouter from Plan 03 — extend; access-check pattern)
- apps/api/tests/routes/lists.test.ts (item stubs) - apps/api/tests/routes/lists.test.ts (item stubs)
@@ -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). 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).
</action> </action>
<verify> <verify>
<automated>pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts src/lib/rank.test.ts && pnpm --filter @familysync/api typecheck</automated> <automated>pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts tests/lib/rank.test.ts && pnpm --filter @familysync/api typecheck</automated>
</verify> </verify>
<acceptance_criteria> <acceptance_criteria>
- rank.ts tests green; ordering stable. - rank.ts tests green; ordering stable.
@@ -172,7 +172,7 @@ Output: item endpoints on listsRouter (POST items, per-field PATCH, DELETE); ran
</threat_model> </threat_model>
<verification> <verification>
<automated>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</automated> <automated>pnpm --filter @familysync/api exec vitest run tests/routes/lists.test.ts tests/lib/rank.test.ts && pnpm --filter @familysync/pwa exec vitest run src/routes/ListDetail.test.tsx</automated>
- `playwright-cli`: add / check / delete items in a real browser. - `playwright-cli`: add / check / delete items in a real browser.
</verification> </verification>
@@ -21,7 +21,7 @@ dependency_graph:
- apps/api/src/routes/lists.ts (item routes added, listItemsRouter exported) - apps/api/src/routes/lists.ts (item routes added, listItemsRouter exported)
- apps/api/src/index.ts (listItemsRouter mounted at /api/list-items) - apps/api/src/index.ts (listItemsRouter mounted at /api/list-items)
- apps/api/src/lib/rank.ts (new) - apps/api/src/lib/rank.ts (new)
- apps/api/src/lib/rank.test.ts (new) - apps/api/tests/lib/rank.test.ts (new)
- apps/api/tests/routes/lists.test.ts (item route tests added) - apps/api/tests/routes/lists.test.ts (item route tests added)
- apps/pwa/src/api/listsClient.ts (item functions added) - apps/pwa/src/api/listsClient.ts (item functions added)
- apps/pwa/src/routes/ListDetail.tsx (placeholder replaced with real implementation) - apps/pwa/src/routes/ListDetail.tsx (placeholder replaced with real implementation)
@@ -41,7 +41,7 @@ tech_stack:
key_files: key_files:
created: created:
- apps/api/src/lib/rank.ts - apps/api/src/lib/rank.ts
- apps/api/src/lib/rank.test.ts - apps/api/tests/lib/rank.test.ts
- apps/pwa/src/components/ItemRow.tsx - apps/pwa/src/components/ItemRow.tsx
- apps/pwa/src/components/AddItemInput.tsx - apps/pwa/src/components/AddItemInput.tsx
modified: modified:
@@ -80,7 +80,7 @@ metrics:
| Task | Name | Commit | Files | | Task | Name | Commit | Files |
|------|------|--------|-------| |------|------|--------|-------|
| RED | Failing tests for item routes + rank helpers | b1dc9b8 | tests/routes/lists.test.ts, src/lib/rank.test.ts | | RED | Failing tests for item routes + rank helpers | b1dc9b8 | tests/routes/lists.test.ts, tests/lib/rank.test.ts |
| GREEN | rank.ts + item endpoints + listItemsRouter + index.ts mount | 5e31514 | rank.ts, lists.ts, index.ts | | GREEN | rank.ts + item endpoints + listItemsRouter + index.ts mount | 5e31514 | rank.ts, lists.ts, index.ts |
| 2 | ListDetail + ItemRow + AddItemInput + listsClient item fns | 6da9c2a | 5 files (2 new, 3 modified) | | 2 | ListDetail + ItemRow + AddItemInput + listsClient item fns | 6da9c2a | 5 files (2 new, 3 modified) |
@@ -107,7 +107,7 @@ Ran against `http://localhost:5173/lists/284` (list id 284, Test Groceries) with
## Verification Results ## Verification Results
### API Tests ### API Tests
- `tests/routes/lists.test.ts + src/lib/rank.test.ts`: 48 passed (0 failed) - `tests/routes/lists.test.ts + tests/lib/rank.test.ts`: 48 passed (0 failed)
- rank.ts pure unit tests: 8 passed (rankForAppend/rankBetween ordering/stability) - rank.ts pure unit tests: 8 passed (rankForAppend/rankBetween ordering/stability)
- Item POST assigns rank "a0" for first item; subsequent items rank > prior — PASS - Item POST assigns rank "a0" for first item; subsequent items rank > prior — PASS
- Per-field PATCH zod refine (exactly one field) — two-field body → 400 — PASS - Per-field PATCH zod refine (exactly one field) — two-field body → 400 — PASS
@@ -152,7 +152,7 @@ No new threat surface beyond the plan's trust boundaries.
## Self-Check: PASSED ## Self-Check: PASSED
- `apps/api/src/lib/rank.ts` — FOUND - `apps/api/src/lib/rank.ts` — FOUND
- `apps/api/src/lib/rank.test.ts` — FOUND - `apps/api/tests/lib/rank.test.ts` — FOUND
- `apps/api/src/routes/lists.ts` (POST /:id/items route) — FOUND - `apps/api/src/routes/lists.ts` (POST /:id/items route) — FOUND
- `apps/api/src/index.ts` (listItemsRouter mounted at /api/list-items) — FOUND - `apps/api/src/index.ts` (listItemsRouter mounted at /api/list-items) — FOUND
- `apps/pwa/src/components/ItemRow.tsx` — FOUND - `apps/pwa/src/components/ItemRow.tsx` — FOUND
@@ -8,7 +8,7 @@ files_modified:
- apps/pwa/src/routes/ListDetail.tsx - apps/pwa/src/routes/ListDetail.tsx
- apps/pwa/src/components/ItemRow.tsx - apps/pwa/src/components/ItemRow.tsx
- apps/pwa/src/api/listsClient.ts - apps/pwa/src/api/listsClient.ts
- apps/api/src/lib/rank.test.ts - apps/api/tests/lib/rank.test.ts
- apps/api/tests/routes/lists.test.ts - apps/api/tests/routes/lists.test.ts
autonomous: true autonomous: true
requirements: [LIST-03] requirements: [LIST-03]
@@ -97,9 +97,9 @@ Output: dnd-kit DndContext/SortableContext in ListDetail; sortable ItemRow with
<task type="auto"> <task type="auto">
<name>Task 2: Strengthen server-side reorder ordering tests (LIST-03, D-13)</name> <name>Task 2: Strengthen server-side reorder ordering tests (LIST-03, D-13)</name>
<files>apps/api/src/lib/rank.test.ts, apps/api/tests/routes/lists.test.ts</files> <files>apps/api/tests/lib/rank.test.ts, apps/api/tests/routes/lists.test.ts</files>
<read_first> <read_first>
- apps/api/src/lib/rank.test.ts (from Plan 04) - apps/api/tests/lib/rank.test.ts (from Plan 04)
- apps/api/tests/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-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) - .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. 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.
</action> </action>
<verify> <verify>
<automated>pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts tests/routes/lists.test.ts</automated> <automated>pnpm --filter @familysync/api exec vitest run tests/lib/rank.test.ts tests/routes/lists.test.ts</automated>
</verify> </verify>
<acceptance_criteria> <acceptance_criteria>
- LIST-03 ordering test ("PATCH new rank produces correct fractional order") is present and green. - 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
</threat_model> </threat_model>
<verification> <verification>
<automated>pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts tests/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit</automated> <automated>pnpm --filter @familysync/api exec vitest run tests/lib/rank.test.ts tests/routes/lists.test.ts && pnpm --filter @familysync/pwa exec tsc --noEmit</automated>
- `playwright-cli`: drag-reorder persists across reload. - `playwright-cli`: drag-reorder persists across reload.
</verification> </verification>
@@ -16,7 +16,7 @@ dependency_graph:
affects: affects:
- apps/pwa/src/components/ItemRow.tsx (useSortable + handle listeners) - apps/pwa/src/components/ItemRow.tsx (useSortable + handle listeners)
- apps/pwa/src/routes/ListDetail.tsx (DndContext/SortableContext/useSensors/onDragEnd) - apps/pwa/src/routes/ListDetail.tsx (DndContext/SortableContext/useSensors/onDragEnd)
- apps/api/src/lib/rank.test.ts (precision + between-neighbors tests) - apps/api/tests/lib/rank.test.ts (precision + between-neighbors tests)
- apps/api/tests/routes/lists.test.ts (5 LIST-03 ordering tests) - apps/api/tests/routes/lists.test.ts (5 LIST-03 ordering tests)
tech_stack: tech_stack:
added: [] added: []
@@ -32,7 +32,7 @@ key_files:
modified: modified:
- apps/pwa/src/components/ItemRow.tsx (useSortable + handle listeners + D-14 transition) - apps/pwa/src/components/ItemRow.tsx (useSortable + handle listeners + D-14 transition)
- apps/pwa/src/routes/ListDetail.tsx (DndContext + SortableContext + useSensors + onDragEnd) - apps/pwa/src/routes/ListDetail.tsx (DndContext + SortableContext + useSensors + onDragEnd)
- apps/api/src/lib/rank.test.ts (2 new tests: precision + between-neighbors) - apps/api/tests/lib/rank.test.ts (2 new tests: precision + between-neighbors)
- apps/api/tests/routes/lists.test.ts (5 new LIST-03 ordering tests) - apps/api/tests/routes/lists.test.ts (5 new LIST-03 ordering tests)
decisions: decisions:
- "@dnd-kit/utilities not installed as direct dependency; transformToString inlined (5-line function identical to CSS.Transform.toString) to avoid adding a redundant dep" - "@dnd-kit/utilities not installed as direct dependency; transformToString inlined (5-line function identical to CSS.Transform.toString) to avoid adding a redundant dep"
@@ -85,7 +85,7 @@ Tested against `http://localhost:5173/lists/358` (list id 358, "Test Drag List",
## Verification Results ## Verification Results
### API Tests ### API Tests
- `src/lib/rank.test.ts`: 10 passed (0 failed) — includes new precision test (100-iteration zipper inserts) and between-neighbors contract - `tests/lib/rank.test.ts`: 10 passed (0 failed) — includes new precision test (100-iteration zipper inserts) and between-neighbors contract
- `tests/routes/lists.test.ts`: 45 passed (0 failed) — includes 5 new LIST-03 ordering tests - `tests/routes/lists.test.ts`: 45 passed (0 failed) — includes 5 new LIST-03 ordering tests
- Combined: 55 passed (0 failed) - Combined: 55 passed (0 failed)
@@ -118,7 +118,7 @@ No new threat surface introduced.
- `apps/pwa/src/components/ItemRow.tsx` — FOUND (useSortable imported and used) - `apps/pwa/src/components/ItemRow.tsx` — FOUND (useSortable imported and used)
- `apps/pwa/src/routes/ListDetail.tsx` — FOUND (DndContext, SortableContext, generateKeyBetween imported and used) - `apps/pwa/src/routes/ListDetail.tsx` — FOUND (DndContext, SortableContext, generateKeyBetween imported and used)
- `apps/api/src/lib/rank.test.ts` — FOUND (precision + between-neighbors tests present) - `apps/api/tests/lib/rank.test.ts` — FOUND (precision + between-neighbors tests present)
- `apps/api/tests/routes/lists.test.ts` — FOUND (5 LIST-03 reorder tests added) - `apps/api/tests/routes/lists.test.ts` — FOUND (5 LIST-03 reorder tests added)
- Commit d49c5f1 (Task 1) — FOUND - Commit d49c5f1 (Task 1) — FOUND
- Commit ef4b115 (Task 2) — FOUND - Commit ef4b115 (Task 2) — FOUND
@@ -2,11 +2,11 @@
* Unit tests for rank.ts fractional-indexing helpers (D-13). * Unit tests for rank.ts fractional-indexing helpers (D-13).
* *
* Pure function tests, no DB needed. * Pure function tests, no DB needed.
* Run: pnpm --filter @familysync/api exec vitest run src/lib/rank.test.ts * Run: pnpm --filter @familysync/api exec vitest run tests/lib/rank.test.ts
*/ */
import { describe, it, expect } from 'vitest' import { describe, it, expect } from 'vitest'
import { rankForAppend, rankBetween } from './rank.js' import { rankForAppend, rankBetween } from '../../src/lib/rank.js'
describe('rankForAppend', () => { describe('rankForAppend', () => {
it('returns "a0" when list is empty (no existing rank)', () => { it('returns "a0" when list is empty (no existing rank)', () => {