Files
RenewCMS/features/auth_shell_login_conformance.qa.md
T

89 lines
6.4 KiB
Markdown

# QA: AuthShell and log-in screen conform to the design spec
## Automated (Vitest + Vue Test Utils, `task test:web`)
No `/v1` calls are relevant to these assertions; mount AuthShell and LoginView directly (LoginView
already needs `useApi`/`GET /v1/auth/registration` mocked per features/login_screen.qa.md's setup,
reused here only as scaffolding, not as the thing under test).
1. **AppLogo renders inline SVG with no edge in either mode** — mount AuthShell with title
"Log in"; assert an inline `<svg>` (not `<img>`) renders as UPageCard's first child element,
left-aligned (not centered) above the title/description block, sharing the card's 24px gap, at
32px, with `role="img" aria-label="RenewCMS"`, and is not inside an `<a>`; assert its outer
square has no stroke in light mode; switch to dark mode (toggle the `.dark` class the way
`nuxt_ui_shell_foundation`'s color-mode tests do) and assert the outer square still has no
stroke, per `docs/design/source/AuthCard.dc.html`'s literal, non-theme-branched
`edge: 'transparent'`.
2. **UPageCard title is an h1 with tabindex="-1"** — mount AuthShell with title "Log in" and
description "Welcome back. Log in to manage your articles."; assert
`wrapper.find('h1').attributes('tabindex')` is `"-1"` and its text is "Log in"; assert the
description text "Welcome back. Log in to manage your articles." renders via UPageCard's
`description` prop (not as a sibling `<p>` hand-authored in AuthShell's template). This
replaces the older assertion in `AuthShell.spec.ts` that only checked for any `<h1>`; keep that
assertion passing (h1 text still equals the title) while adding the tabindex check.
3. **Muted background at sm and up** — mount AuthShell at a `>= 640px` viewport (mock
`useBreakpoints`/matchMedia the way other shell tests do); assert `<main>`'s class list
includes the muted background utility (e.g. `bg-muted`); assert the card renders with a
border and is capped at 400px width, offset 12vh from the top.
4. **Default background, borderless card, 20px padding, xl controls below sm** — mount AuthShell
at a `< 640px` viewport; assert `<main>`'s class list includes the default background utility
(`bg-default`) and not the muted one; assert the card has no border class; assert the card's
padding is 20px; assert the Username/Password inputs and submit button render at `size="xl"`.
5. **Login form is a UForm** — mount LoginView at /login; assert the form wrapping the fields is
a UForm component instance, not a bare `<form>` element with only `@submit.prevent` wired by
hand.
6. **Forgot password in the #hint slot** — mount LoginView at /login; assert the Password
UFormField is passed content (or renders content) in its `hint` slot containing a
"Forgot password?" link to /register/reset/request; assert the field's rendered label text is
exactly "Password" with no link inside it.
7. **Inputs default to neutral, then highlight red on error** — mount LoginView at /login; assert
the Username and Password `UInput` components render with `highlight` falsy (or absent) and
the theme's default ring class (`ring-(--ui-border-accented)`); then trigger the Validation
errors state (type "ma" into Username, submit with Password empty); assert both `UInput`s now
receive `:highlight="true"` (or the field's error is otherwise truthy) so the edge renders in
`--ui-error`, alongside "Use at least 3 characters." and "Enter your password." respectively.
### Implementation finding for coder
`web/src/views/LoginView.vue`'s Username and Password `UInput`s currently receive no `:highlight`
prop at all — `UFormField` gets `:error="usernameError"` / `:error="passwordError"`, but that value
is never forwarded to the inner `UInput`. Today the edge never turns red in the Validation errors
state; this isn't a stale/inverted binding, it's a missing one. Wiring `:highlight="!!usernameError"`
/ `:highlight="!!passwordError"` (or equivalent) onto each `UInput` is the fix scenario 7 above
pins down.
## Visual (manual verification — desktop and mobile, light and dark)
Reference: `docs/design/source/RenewCMS Screens Auth.dc.html`, group "Log in", plus
`docs/design/source/RenewCMS Components Product.dc.html`'s AuthShell drawing and
`docs/design/source/RenewCMS Components Primitives.dc.html`'s Input drawing.
- [ ] AppLogo renders inside UPageCard as its first element, left-aligned above the title (not
centered above the card), sharing the card's 24px gap; the mark matches the favicon.svg
drawing exactly (white R on a black square), desktop and mobile; no edge stroke is visible
around the square in either light or dark mode.
- [ ] UPageCard title ("Log in") renders at the card-title size/weight from the AuthShell drawing
and receives focus (visible focus ring) on route change; description text matches
"Welcome back. Log in to manage your articles." styling, desktop and mobile, light and dark.
- [ ] At sm and up: 400px card with its border, 12vh top offset, on the muted page canvas, light
and dark.
- [ ] Below sm: card fills the screen borderless with 20px padding on the default (not muted)
background; fields and the submit button render at the touch (xl, 44px) size, light and
dark.
- [ ] The Password field's "Forgot password?" link sits right-aligned on the label row (the hint
position), matching the Auth board, desktop and mobile, light and dark.
- [ ] Username and Password fields show the neutral control-edge border by default; in the
Validation errors state (short username, empty password) both fields' edges turn to the
error color alongside their messages, in both light and dark.
- [ ] Keyboard/focus: Tab order remains Username → Password → show/hide toggle → "Forgot
password?" → submit; UPageCard's h1 is reachable/focusable via tabindex="-1" on route
change, matching AuthShell's existing a11y spec.
## Manual verification
- **AppLogo reused in DashboardShell** — out of scope for this slice (AuthShell/login only).
`DashboardShell.vue`'s sidebar header is currently a plain `<span class="font-semibold">
RenewCMS</span>` (not AppLogo), and its footer is a bare `<span>Log out</span>` instead of the
UserMenu component components.md specifies. Both need their own "Built from" conformance pass in
a later DashboardShell slice; AppLogo (built here with a `size` prop) will be ready to drop in
at that point without changes.