6 Commits

Author SHA1 Message Date
Bas van Rossem
9c99d56f99 test(api): Admin users — fill gaps + lifecycle test
Fill the remaining coverage gaps in src/routes/admin-users.ts and add the
domain lifecycle test, bringing the file to 100% stmts/branch/funcs/lines.

New tests (apps/api/test/admin-users.test.ts):
- password route: 404 unknown id; 400 when better-auth setUserPassword throws
  (driven via a spy so the catch path is deterministic).
- toListItem: a null DB role lists as 'worker' (nullish-coalescing fallback).
- role route: 400 on an invalid role body; 404 on an unknown id.
- reactivate route: 404 on an unknown id.

Lifecycle (apps/api/test/integration/user-lifecycle.test.ts): admin creates a
worker -> worker signs in and the bearer authorizes /api/me -> admin deactivates
(session rows deleted, so the pre-issued token 401s and fresh sign-in is blocked)
-> admin reactivates -> sign-in works again.

The two last-admin guards (role + deactivate routes) are unreachable over HTTP
(the self-demote / self-deactivate guards above already handle caller===target,
so any caller reaching them is a distinct active admin and
activeAdminsExcluding(target) >= 1). Annotated with /* c8 ignore */ + reasons
rather than left as silent gaps; the guard logic is unit-tested via
activeAdminsExcluding.

No production behavior changed; no bugs found.
2026-07-23 13:43:59 +02:00
Bas van Rossem
31d13a8381 test(api): Reports + admin export — fill gaps + lifecycle test
Drives the report/export parts of src/routes/admin.ts to 100%
stmts/branch/funcs/lines. Adds one lifecycle test plus gap tests for the
previously-uncovered branches; no production behavior changed.

Tests added (apps/api/test):
- report.test.ts: invalid insole_type / non-numeric activity_id → 400;
  activity filter narrows; null insole_type bucketed "Onbekend"; null
  duration counts as 0 worked; export 400 on missing/inverted range.
  Migrated the report + export describes to resetDb(beforeEach) so exact
  totals are order-independent (removed the activity_id isolation
  workaround in the all-users export test).
- integration/report-aggregation.test.ts: lifecycle — 2 workers × 2
  activities × 2 types → exact totals + every by_worker/by_activity/
  by_type row (values and worked-desc order) → user_id filter narrows.

Defensive annotations in admin.ts report loop (behavior unchanged):
- pausedSeconds/pairCount ?? 0 — NOT NULL columns, DB-impossible nulls.
- user_name/activity_name ?? 'Onbekend' — unreachable; userId FK cascades
  on delete and activityId FK is enforced (libsql enforces FKs), so every
  session always joins to a real user and activity.

No bugs found; the code was already correct.
2026-07-22 13:03:04 +02:00
Bas van Rossem
bdf65ae685 test(api): Admin sessions — fill gaps + lifecycle test
Fills the session-part coverage gaps in src/routes/admin.ts (cross-user list,
active list, manual create/edit, admin stop/discard) and adds the admin↔worker
lifecycle test.

New route-level tests (apps/api/test/admin.test.ts):
- manual create: 400 on schema-invalid body; 400 when paused_seconds > span.
- edit: 404 non-numeric id; 400 schema-invalid body; 400 unparseable start_time;
  400 paused_seconds > span; 404 unknown activity.
- stop: 404 non-numeric/unknown id; folds an open pause into paused_seconds.
- discard: 404 non-numeric/unknown id; 409 when already closed.

Lifecycle (apps/api/test/integration/admin-worker-session.test.ts): worker
starts → admin stops via the admin endpoint → session lands in /api/admin/report
and /api/admin/export with matching totals (uses resetDb for exact counts).

admin.ts session parts now at 100% stmts/lines; every session-part branch
covered. The one remaining session-part branch (row.pausedSeconds ?? 0 in the
stop route) is c8-ignored — paused_seconds is NOT NULL DEFAULT 0, so the null
branch is DB-impossible. The remaining uncovered branches in admin.ts are the
report/export parts, owned by the Reports domain (B-A6).

No behavior-changing bugs found; all session-part code was already correct.
2026-07-22 12:41:52 +02:00
Bas van Rossem
9ecbf952d3 test(api): Work-sessions — fill gaps + lifecycle test
Drives src/routes/sessions.ts and src/lib/work-session.ts to 100%
stmts/branch/funcs/lines (branch was 84.12% / 83.33%).

- sessions.test.ts: added error/edge branch tests — malformed-JSON start
  (400), non-numeric id on pause/resume/stop/discard (404), pause/resume of a
  no-longer-active session (409), discard missing (404) + already-closed (409),
  stop missing (404), and discard ownership scoping (user B → 404).
- work-session.test.ts: mapper unit tests — null insoleType, nullish
  pausedSeconds → 0, null durationSeconds/notes, full-field shape with
  activity/user opts, and opts defaulting to undefined.
- test/integration/worker-session-lifecycle.test.ts: the anchor lifecycle test
  (start→pause→resume→stop→history→export).

No bugs found — the code was correct. The two remaining uncovered branches were
the defensive `row.pausedSeconds ?? 0` guards in resume/stop; pausedSeconds is
NOT NULL DEFAULT 0 in the schema, so the null branch is unreachable via any
route. Annotated both with `/* c8 ignore next -- reason */` (comment only, no
behavior change).
2026-07-22 12:14:32 +02:00
Bas van Rossem
af7251398c test(api): Activities — fill gaps + lifecycle test 2026-07-22 12:01:03 +02:00
Bas van Rossem
e6e4ca0a1e test(api): Auth & /me — fill gaps + lifecycle test 2026-07-22 11:50:32 +02:00