feat: SPA Roles screens
This commit is contained in:
1 parent
907949aa12
commit
3db490a615
47 files changed
+6947
-9
No files matched your search
@@ -0,0 +1,52 @@
|
||||
# QA procedure: SPA Roles screens (slice 6)
|
||||
|
||||
Spec: features/roles_spa_screens.feature. Vitest + Vue Test Utils under `task test:web`, /v1 mocked through the existing kits, access bodies built with web/src/test/access.ts. No live server, no real SMTP. Visual checks are out of this slice by user decision.
|
||||
|
||||
## Honesty rules
|
||||
0. First run `task test:web` on the unmodified tree and record the baseline (exit code, failing specs).
|
||||
1. If the runner cannot execute, every SPA item is NOT RUN, never passing.
|
||||
2. Report each new or edited spec and which already failed in the baseline.
|
||||
3. Spec only the copy the design gives. Items marked TBD in the feature (reset, review differences, duplicate note, types without schema.view, templates beyond the examples, role_not_found) get behaviour specs that don't assert text, and are listed as design gaps.
|
||||
4. Date and clock: fixed `updated_at` strings, a pinned time zone or injected formatter for "11:02"; no spec freezes the system date.
|
||||
|
||||
## Automated (Vitest)
|
||||
| Spec | Cases |
|
||||
|---|---|
|
||||
| router/__tests__/rolesRoutes.spec.ts (new) | the route table of the feature; /settings/permissions redirect with no 403 flash; typed guard with the session checking |
|
||||
| components/__tests__/DashboardShell.spec.ts (extend) | Access > Roles entry with roles.view in sidebar and drawer, absent without it, no Permissions entry |
|
||||
| composables/__tests__/useRoles.spec.ts (new) | list, get, create, update, delete, reassign, reset calls; error mapping of every refusal code; role_conflict re-read of updated_by |
|
||||
| lib/__tests__/rolePreview.spec.ts (new) | every sentence of the design, grouping of types, Nothing granted, Changed tagging, read-only wording, members line |
|
||||
| lib/__tests__/roleForm.spec.ts (new) | form from role, grants to payload (wildcard plus typed, none omitted, owner-only never sent), Reset of a Custom row, presets, unsaved counter, discard |
|
||||
| lib/__tests__/grantLocks.spec.ts (new) | escalation locks via scopeOf (all vs own, typed none), owner-only items, picker disabling |
|
||||
| views/__tests__/RolesListView.spec.ts (new) | Default, Loading (150 ms with fake timers), Only built-in, Error with retry, No permission to edit, row menus, mobile cards |
|
||||
| views/__tests__/RoleEditorView.spec.ts (new) | New role, Editing, Built-in as owner / admin, Owner locked, own role, view-only, Unsaved, Saving, Saved, name required / taken, Conflict, 403 lowered, escalation and role_locked answers, create then route replace, duplicate prefill |
|
||||
| components/__tests__/PermissionGrid.spec.ts (covers PresetPills and OnOffCell), ScopeControl.spec.ts, PermissionGroup.spec.ts (new) | roles/names ("Events: Update"), keyboard (arrows, Home, End, Space, roving tabindex), live region text, aria-disabled and reason, changed marker, "x of y enabled", expand all |
|
||||
| components/__tests__/RolePreview.spec.ts (new) | card on desktop, 92% sheet on mobile, Close |
|
||||
| components/__tests__/DeleteRoleDialog.spec.ts (covers RolePicker through pickerKit.ts) (new) | Blocked, picker disabled reasons, Move and delete sequence and each failure, Confirm no members, built-in dialog, role_has_members live count |
|
||||
| lib/__tests__/grantKey.spec.ts (new) | parseGrantKey and formatGrantKey split on the first colon, type key containing a colon through form, locks and names |
|
||||
| i18n/roleMessages.spec.ts (new) | new keys exist in EN and FR, placeholders match |
|
||||
|
||||
## Manual checks
|
||||
1. Keyboard: tab order across the grid (one stop per cell), arrows, Home and End; disabled items reach focus and announce their reason; focus visible.
|
||||
2. Screen reader: live region announces "Events, Update, set to Own."; sticky bar and sheet focus return.
|
||||
3. Two browsers: owner edits Contributor while an admin has it open, then the admin's Save gets the Conflict state with the real name and time.
|
||||
4. Lower a role while its editor is open in another tab: the next refused save shows "Your access changed".
|
||||
5. Real flow in a real browser: create Contributor with Write own, assign it from Users, delete Intern, delete Contributor with reassign.
|
||||
6. Mobile 390 px: card grid, sticky bar and sheet; touch targets 44 px. French copy. Dark mode.
|
||||
7. Direct link to /settings/permissions after build: the embedded SPA redirects (a Go 301 is not implemented).
|
||||
8. `task lint:web` (eslint and vue-tsc) green; `task test:web` exit 0 on the final tree.
|
||||
|
||||
## Design gaps and backend notes
|
||||
- G1 presets semantics and the "7 unsaved changes" count: a preset touches only the content grid and the count is the number of changed (key, scope) entries, name and description counting 1 each.
|
||||
- G2 "All content types" is the wildcard `content.<action>`; a type row is Custom with a Reset link when it holds a typed grant, including `:none`.
|
||||
- G3 type list without schema.view: the grid shows Articles plus the types named in the role's typed grants, with a note; copy TBD.
|
||||
- G4 reset-to-default button, confirm dialog and toast copy TBD.
|
||||
- G5 "Review differences" read-only Added/Removed/Changed list; copy TBD.
|
||||
- G6 Duplicate at `/settings/roles/new?from=<id>`, query stripped after load; copy TBD.
|
||||
- G7 preview templates beyond the Contributor, Nothing granted and Schema/Media/Authors examples; copy TBD.
|
||||
- G8 `role_not_found` page-level state with "Back to Roles"; copy TBD. `invalid_role_name` maps to "Give the role a name."; other 400 codes show a generic error toast.
|
||||
- G9 the SPA cannot send an HTTP 301: a vue-router client redirect to `/settings/roles`.
|
||||
- G10 the built-in delete dialog is unreachable: component-level spec only.
|
||||
- G11 no leave guard: leaving drops the edits.
|
||||
- G12 after create the route is replaced with `/settings/roles/:id` and the "Role created" toast shows.
|
||||
- No backend change is needed: all routes exist (including POST /v1/role/{id}/reset and updated_by).
|
||||
Reference in new issue
Block a user