test(admin): Users — fill gaps + lifecycle test

This commit is contained in:
Bas van Rossem
2026-07-23 15:07:12 +02:00
parent 5aa6febd65
commit 8a6bc9ea7d
4 changed files with 281 additions and 0 deletions

View File

@@ -479,3 +479,40 @@ Guaranteed behaviors:
`content-disposition` header, and falls back to `solelog-report.csv` when that header is absent.
- Lifecycle (`src/screens/Reports.test.tsx`): pick `Deze maand` + a Medewerker filter → the report
query reflects both (`from` = this-month start, `user_id` set) and the returned rows still render.
## Users — admin client
Src covered (admin `apps/admin`): `src/screens/Users.tsx`, `src/components/UserForm.tsx`, and
`src/api/users.ts` — `UserForm.tsx` and `users.ts` at 100% stmts/branch/funcs/lines; `Users.tsx` at
100% stmts/branch/funcs/lines. Two `c8 ignore`s with reasons in `Users.tsx`: the `usersQuery.data ?? []`
fallback (defensive — the isLoading/isError branches return above it, so `data` is always set) and the
`if (pw.length < 8) return;` guard in `onReset` (defensive — the Opslaan button is disabled while the
password is shorter than 8, so it never fires).
Guaranteed behaviors:
- The screen lists one row per user with a role pill (`Beheerder`/`Werker`) and a status pill
(`Actief`/`Inactief`), plus name, email, and a locale-formatted created date.
- The signed-in admin's own row (matched by `useMe().user.id`) shows a `jij` badge and hides the
role-toggle and deactivate/reactivate actions (a user can never demote or deactivate themselves via
the UI); other rows show those actions.
- The loading state renders `Laden…` and the query error state renders `Kon gebruikers niet laden.`.
- `+ Nieuwe gebruiker` toggles the create form; submitting it POSTs a `CreateUserInput`
(`{ name, email, password, role }`) to `/api/admin/users`; `Annuleer` closes the form without a POST.
- Create errors surface inline as `E-mailadres bestaat al of ongeldig.` (the `useCreateUser` onError
path), which renders in the `UserForm` error slot.
- `UserForm`: name/email are trimmed into the payload and the selected `Rol` is carried through; a
password shorter than 8 shows `Minstens 8 tekens.` and blocks submission (the `password.length < 8`
guard); the submit button is disabled while `pending`.
- The role button promotes a worker to admin (`{ role: 'admin' }`) or demotes an admin to worker
(`{ role: 'worker' }`) via `POST /api/admin/users/:id/role`.
- Inline password reset: `Reset wachtwoord` reveals a password field with `Opslaan`/`Annuleer`;
`Opslaan` stays disabled until the new password is at least 8 chars, then POSTs `{ password }` to
`/api/admin/users/:id/password` and closes the field on success; `Annuleer` closes it without a POST.
- `Deactiveer` POSTs to `/api/admin/users/:id/deactivate` (shown on active peers) and `Heractiveer`
POSTs to `/api/admin/users/:id/reactivate` (shown on inactive peers).
- Every mutation (`create`/`setRole`/`resetPassword`/`deactivate`/`reactivate`) invalidates the
`['admin','users']` query so the list refetches and reflects the change.
- Lifecycle (`src/screens/Users.test.tsx`): create a worker via the form → it appears in the refreshed
list as `Werker` → promote it via `Maak admin` → the pill flips to `Beheerder` after the refetch →
reset its password inline (`Opslaan`) → the POST fires and the inline field closes.