5.1 KiB
Domain test checklist — guaranteed behaviors
Living definition-of-done. Each domain lists the behaviors its tests guarantee.
When you change a domain, its box must still hold (or you update this list on purpose).
Baseline established 2026-07-22 (see plan 2026-07-22-per-domain-test-safety-net).
Tracked as Plane epic SL-70.
Coverage baseline (Phase A, 2026-07-22)
| Workspace | % Stmts | % Branch | % Funcs | % Lines |
|---|---|---|---|---|
| api | 96.94 | 74.29 | 100 | 96.94 |
| worker | 89.62 | 87.42 | 70.58 | 89.62 |
| admin | 92.43 | 84.91 | 78.75 | 92.43 |
Target after the sweep: near-100% per domain; remaining uncovered lines annotated
/* c8 ignore next -- <reason> */, not left silent.
Infra (health/db/schema/seed/env/migrate)
Src covered: src/routes/health.ts, src/db/client.ts, src/db/ensure-dir.ts,
src/db/migrate.ts, src/db/seed.ts, src/env.ts — all at 100% stmts/branch/funcs/lines.
(src/db/schema.ts is generated and excluded from coverage by config.)
Guaranteed behaviors:
GET /healthreturns{ status: 'ok' }.env.tsapplies every dev default (DATABASE_URL,BETTER_AUTH_SECRET,BETTER_AUTH_URL,PORT,WEB_ORIGINS) when the vars are unset, and reads each override when set (PORTcoerced to a number).env.WEB_ORIGINSparsesCORS_ORIGINSinto a list, trimming whitespace and dropping empty entries; falls back to the default localhost origins whenCORS_ORIGINSis empty/unset.runMigrations()is idempotent — re-running it against an already-migrated DB does not throw.ensureDbDir()is a no-op for non-file:URLs and for a bare filename in the current dir.seed()seeds the reference activities idempotently and seeds the dev worker + dev admin with the correct roles, idempotently.seed()never creates the dev users whenNODE_ENV=production(reference activities still seeded).- The
migrate.ts/seed.tsCLI direct-run blocks arec8 ignored — unreachable under the test runner (exercised only viatsx src/db/{migrate,seed}.ts).
Auth & /me
Src covered: src/auth.ts, src/routes/me.ts, src/lib/require-user.ts, and the CORS
middleware in src/app.ts — all at 100% stmts/branch/funcs/lines.
Guaranteed behaviors:
- Sign-in with valid credentials returns a bearer token (
set-auth-tokenheader); sign-in with a wrong password fails (status ≥ 400). - Public sign-up is rejected (
disableSignUp— admin creates users). GET /api/mereturns 401 without a token, and{ user: { id, email, name, role } }with a valid bearer; role reflects the user (worker/admin).GET /api/mefalls back to role'worker'when the session user has no role set.getSessionUsermapsid,role, andbannedfrom the session; defaultsroleto'worker'andbannedtofalsewhen unset; returnsnullwhen there is no session.isAdminis true only for theadminrole (false forworkerand fornull).adminGuardreturns 401 without a session, 403 for a non-admin, and 403 for a banned admin that still holds a valid token; it passes through for an active admin. (Exercised through the/api/admin/*surface inadmin-users.test.ts.)- CORS: the allowed SPA origins (worker 5173, admin 5174) are echoed on the
access-control-allow-originheader, OPTIONS preflight is answered with the allowed methods, andset-auth-tokenis exposed so the SPA can read the bearer on sign-in.
Activities
Src covered: src/routes/activities.ts — 100% stmts/branch/funcs/lines. The one unreachable
branch (row.sortOrder ?? 0 in toActivity; sort_order is NOT NULL DEFAULT 0) is
c8 ignored with a reason, not left silent.
Guaranteed behaviors:
GET /api/activitiesrequires a session (401 without a token); any authenticated user — worker or admin — may read.- The list is ordered by
sort_orderthenname, and?insole_type=<type>filters to activities whoseinsole_typesinclude that type. POST/PUT/DELETE/PUT /reorderare admin-only: 401 without a token, 403 for a worker.- Create validates a non-empty (trimmed)
name(400 otherwise) and defaultsinsole_typesto all three (Kurk,Berk,3D) when omitted. - Create appends the new activity with a
sort_orderone higher than the current maximum. insole_typesround-trips through create/list as the exact stored subset.- Update (
PUT /:id) 404s for a non-numeric or unknown id, 400s on an invalid body, and returns the updated activity otherwise. - Delete (
DELETE /:id) 404s for a non-numeric id, removes the activity and its work-session rows (no FK cascade), and returns{ success: true }. - Reorder (
PUT /reorder) setssort_orderfrom theidsarray position; it 400s on an empty array (zodmin(1)) and when the ids are not exactly the full known set (wrong count or an unknown id). - Lifecycle: an admin creates three activities → reorders them → a worker's GET reflects the new order → the admin deletes one → it is gone from the list.