Study/audit-results/TEST_GAPS.md

4.5 KiB
Raw Permalink Blame History

Test Gaps

Current suite: 6 files / 30 tests — 20 in src/lib/arcade/* (out of scope) + 10 in src/lib/spacedRepetition.test.ts (pure scheduling math only). No test touches a service, an API route, the database, auth, scoring, imports, or progress. CI never runs npm test. Gaps ranked by user-impact × regression-likelihood.

ID Area Gap Risk it would fail to catch Suggested test
TEST-GAP-01 Auth (FIN-02/08/09/10) authService.ts (login, lockout, first-login provisioning, reset token, generation bump) and session config have zero tests Session-secret fallback regression, lockout bypass, generation-bump loss (stolen sessions stay valid) Extract + unit-test getLockoutDuration thresholds, parseResetTokenRecord; service tests with temp SQLite + fake timers: 5 wrong passwords → 423; locked-out login rejected; success resets counter; completePasswordReset bumps generation
TEST-GAP-02 Scoring (FIN-03/11/26/27) src/lib/scoring.ts SATA partial credit has zero tests Wrong grades silently persisted into every attempt — permanent data corruption scoreQuestion: SATA 2/4 correct select both → 1; 1 correct + 1 wrong → 0; over-select → 0; MC multi-select first-wrong → 0; scoreQuiz with missing question keys; 0-correct SATA → 0 (not NaN)
TEST-GAP-03 Quiz attempt persistence (FIN-03/12/13) POST /api/quizzes/[id]/attempt + partial-retake filter + progressService.upsertProgress asymmetry (DECK writes cardResultsJson, QUIZ writes answersJson) have zero tests Retake-scoring regression (FIN-03 class), duplicate attempts, progress column clobbering Route/service test: partial retake answering 2 of 5 → maxScore 2, score from those 2; upsert round-trip preserves the respective JSON columns
TEST-GAP-04 SRS service (FIN-16/35) spacedRepetitionService.ts (reviewCard optimistic concurrency, findNextCard precedence, removeDeck transaction, addDeck validations) has zero tests — only the pure lib is tested Double-review stale write, due/new-card precedence break, cross-class membership, P2002 → 500 Seed class→deck→cards→set on temp DB: stale expectedStateVersion → 409; due before new before learn-ahead; new card with limit 0 rejected; removeDeck atomically deletes states
TEST-GAP-05 Import/repair pipeline (FIN-28/29/30) jsonRepair.ts, importSchemas.ts, shuffle.ts/filterAndClampOrder have zero tests AI-import regression (fences/repair), schema constraint drift (MC exactly-one), resume clamp bugs jsonRepair fence/trailing-comma/broken-JSON cases; schema whitespace/oversize/exactly-one cases; filterAndClampOrder stale-id + overflow cases
TEST-GAP-06 Rate limiter (FIN-10) rateLimiter.ts has zero tests Brute-force guard silently disabled or locking the owner out Fake timers: 10 allowed / 11th blocked with retryAfterMs; window expiry; per-key isolation; custom limits
TEST-GAP-07 Integration harness (FIN-01/21/25) No route tests, no DB-backed tests, no setup file; src/lib/db.ts defaults to file:./dev.db (a naive service test would touch the real dev DB) Migration drift (FIN-01) — nothing would catch a schema/migration mismatch; progress/share/attempt route validation gaps setupFiles + DATABASE_URL=file:<tmp> + prisma migrate deploy in globalSetup; route tests with NextRequest: attempt 200/400/404, reviews 409, share unknown token, login 429
TEST-GAP-08 CI gate (FIN-25) .forgejo/workflows/build.yml runs no tests/lint/prisma validate; no coverage config; no drift check Entire suite can regress with a green pipeline; FIN-01-class drift ships Add npm ci && npm test && npm run lint && npx prisma validate job; prisma migrate diff --from-migrations --to-schema-datamodel gate; container smoke (curl /login on fresh volume); coverage floor
TEST-GAP-09 False confidence (FIN-53) spacedRepetition.test.ts:15-23 "distinct valid state for every rating" never compares ratings scheduleRating collapsing all ratings to one schedule passes the suite Assert pairwise due ordering AGAIN < HARD < GOOD < EASY and distinct due timestamps; graduated-state lapse case

Test-quality positives (verified)

  • spacedRepetition.test.ts is deterministic (fixed now, enable_fuzz: false, no Math.random), tests the real pure module, and asserts exact FSRS intervals.
  • Arcade tests (out of scope) use seeded shuffles and meaningful assertions.
  • No test uses wall-clock time, locale, or network — no flakiness found.