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.
This commit is contained in:
@@ -153,3 +153,36 @@ Guaranteed behaviors:
|
||||
header.
|
||||
- Lifecycle: covered by the worker-session anchor (`test/integration/worker-session-lifecycle.test.ts`),
|
||||
whose final step asserts `GET /api/export` returns the header + exactly one completed-session row.
|
||||
|
||||
## Admin sessions
|
||||
|
||||
Src covered: the session parts of `src/routes/admin.ts` (cross-user list, active list, manual
|
||||
create/edit, admin stop/discard) — all session-part statements, lines, and branches covered, so
|
||||
`admin.ts` is at 100% stmts/lines. The one `row.pausedSeconds ?? 0` guard in the admin stop route
|
||||
is `c8 ignore`d with a reason — `paused_seconds` is `NOT NULL DEFAULT 0`, so the null branch is
|
||||
DB-impossible. (The report/export parts of `admin.ts` — `parseReportQuery`, the aggregation `??`
|
||||
fallbacks, and the export invalid-query branch — are owned and covered by the Reports domain.)
|
||||
|
||||
Guaranteed behaviors:
|
||||
|
||||
- Every `/api/admin/*` session route is gated: 401 without a token, 403 for a worker.
|
||||
- `GET /api/admin/sessions` returns **all** users' sessions newest-first, each joined to
|
||||
`activity_name`, `user_name`, and `user_email`; `GET /api/admin/sessions/active` is the same but
|
||||
filtered to `active` sessions only.
|
||||
- `POST /api/admin/sessions` (manual create): creates a `completed`, `source: 'manual'` session
|
||||
with `duration_seconds = span − paused_seconds` and null `paused_at`; 400 on a schema-invalid
|
||||
body, on `end_time < start_time`, and when `paused_seconds` exceeds the worked span; 404 for an
|
||||
unknown `user_id` and for an unknown `activity_id`.
|
||||
- `PUT /api/admin/sessions/:id` (edit): recomputes `duration_seconds` when `end_time` is present and
|
||||
sets it null when `end_time` is null (re-activating); 404 for a non-numeric or unknown id; 400 on
|
||||
a schema-invalid body, on an unparseable `start_time`, on `end_time < start_time`, and when
|
||||
`paused_seconds` exceeds the span; 404 for an unknown `activity_id`.
|
||||
- `POST /api/admin/sessions/:id/stop`: completes another user's active session, folds an open pause
|
||||
span into `paused_seconds`, clears `paused_at`, and computes `duration_seconds` excluding paused
|
||||
time; 404 for a non-numeric or unknown id; 409 when the session is already closed.
|
||||
- `POST /api/admin/sessions/:id/discard`: marks another user's active session `discarded` with an
|
||||
`end_time`; 404 for a non-numeric or unknown id; 409 when the session is already closed.
|
||||
- Lifecycle (`test/integration/admin-worker-session.test.ts`): a worker starts a session → an admin
|
||||
stops it via the admin endpoint → the completed session appears in `GET /api/admin/report`
|
||||
(totals, `by_worker`, `by_activity`, `by_type` all matching the stored row) and in
|
||||
`GET /api/admin/export` (header + exactly one row, with the leading Worker column).
|
||||
|
||||
Reference in New Issue
Block a user