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.
This commit is contained in:
@@ -222,3 +222,36 @@ Guaranteed behaviors:
|
||||
workers × two activities × two insole types → assert exact totals and every `by_worker`,
|
||||
`by_activity`, `by_type` row (values and descending order) → apply a `user_id` filter → assert the
|
||||
totals and breakdowns narrow to that worker only.
|
||||
|
||||
## Admin users
|
||||
|
||||
Src covered: `src/routes/admin-users.ts` — 100% stmts/branch/funcs/lines. The two last-admin
|
||||
guards (in the role and deactivate routes) are `c8 ignore`d with reasons: they are unreachable
|
||||
over HTTP because 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`; the
|
||||
guard logic itself is unit-tested through `activeAdminsExcluding`.
|
||||
|
||||
Guaranteed behaviors:
|
||||
|
||||
- Every `/api/admin/users*` route is gated: 401 without a token, 403 for a worker, and 403 for a
|
||||
banned admin that still holds a valid token (`adminGuard` defense-in-depth).
|
||||
- `GET /api/admin/users` returns every user ordered by name, each mapped by `toListItem` to
|
||||
`{ id, email, name, role, status, created_at }`; a null DB `role` falls back to `worker` and a
|
||||
`banned` row surfaces as `status: 'inactive'`.
|
||||
- `POST /api/admin/users` creates a user who can then sign in; 409 on a duplicate email; 400 on a
|
||||
schema-invalid body (incl. a password shorter than 8 chars); a mixed-case email is stored
|
||||
lowercased and the created row is returned (no 500 on the re-select).
|
||||
- `POST /:id/role` promotes/demotes and returns the updated row; 400 on an invalid role body; 404 on
|
||||
an unknown id; refuses self-demotion (400); allows demoting a peer admin while the caller stays
|
||||
admin (200).
|
||||
- `activeAdminsExcluding` (unit) counts only active (non-banned) admins and honours the excluded id.
|
||||
- `POST /:id/deactivate` bans the user, clears any live session rows, and returns
|
||||
`status: 'inactive'`; 404 on an unknown id; refuses self-deactivation (400); allows deactivating a
|
||||
peer admin while always blocking self.
|
||||
- `POST /:id/reactivate` clears the ban and returns `status: 'active'`; 404 on an unknown id.
|
||||
- `POST /:id/password` sets a new password (new works, old fails); 400 on a too-short password; 404
|
||||
on an unknown id; surfaces a 400 (not a 500) when better-auth's `setUserPassword` throws.
|
||||
- Lifecycle (`test/integration/user-lifecycle.test.ts`): admin creates a worker → worker signs in
|
||||
and the bearer authorizes `/api/me` → admin deactivates → the session rows are deleted so the
|
||||
pre-issued token no longer authorizes `/api/me` (401) **and** a fresh sign-in is blocked → admin
|
||||
reactivates → the ban is cleared and sign-in works again.
|
||||
|
||||
Reference in New Issue
Block a user