Files
RenewCMS/features/reset_request_screen.qa.md

60 lines
3.8 KiB
Markdown

# QA: Password reset request screen
## Automated (Vitest + Vue Test Utils, `task test:web`)
Mock `useApi` (`POST /v1/auth/password-reset`) per case; no real backend, no httptest server.
Mount ResetRequestPage inside AuthShell with a test router.
1. **Default state** — mount at /register/reset/request; assert heading "Reset your password",
description, Email placeholder "you@example.com" with no value, submit "Send reset link",
footer "Back to log in" linking to /login.
2. **Validation error state** — set Email to "marta@renew", submit; assert the mocked
`POST /v1/auth/password-reset` was never called; assert the error "Enter a full email
address, like name@example.com."
3. **Submitting state** — set Email "marta@renew.example"; mock the call with an unresolved
promise; submit; assert the Email field is disabled and the submit button reads "Sending…"
with a loading indicator.
4. **Sent state** — set Email "marta@renew.example"; mock the call resolving 200; submit; assert
the form is replaced by a ResultPanel (success, mail-check, "Check your email", the neutral
text, note "The link expires in 1 hour.") with a single secondary action "Back to log in";
click it and assert the router's current path is /login.
5. **Too many attempts state** — set Email "marta@renew.example"; mock the call resolving 429
with `Retry-After: 58`; submit; assert an info alert ("Too many requests", "Wait a moment
before asking for another link."); assert Email still reads "marta@renew.example"; assert the
submit button reads "Try again in 0:58" and is disabled; assert the Email field is disabled;
advance fake timers 58s; assert the button re-enables and reads "Send reset link" and the
field is editable again.
6. **Server or network error state** — two sub-cases (500 response, rejected fetch) with Email
"marta@renew.example"; submit; assert an error alert ("Couldn't send the link", "Check your
connection and try again."); assert Email still reads "marta@renew.example" and is re-enabled;
assert the submit button reads "Send reset link" and is no longer loading.
## Visual (manual verification — desktop and mobile, light and dark)
Reference: `docs/design/source/RenewCMS Screens Auth.dc.html`, group "Forgot password". Run
`task visual:check -- forgot-password` for each state.
- [ ] Default state: heading, description, Email field, "Send reset link" button, "Back to log
in" footer link, matches the board exactly.
- [ ] Validation error state: the inline field error renders with the same styling as
Register's/Login's own field errors.
- [ ] Submitting state: disabled field styling and the loading spinner in the submit button.
- [ ] Sent state: ResultPanel (mail-check icon) with its single secondary action, note text below
the description.
- [ ] Too many attempts state: info alert (timer icon), disabled field and disabled button with
the live "Try again in m:ss" countdown text.
- [ ] Server error state: error alert (circle-x icon, no close button), field retains its value.
- [ ] Keyboard/focus: Tab order is Email → submit; the alert (when present) is announced via
`role="status"` (info) or `role="alert"` (error) without re-announcing on re-render; the
ResultPanel's title receives focus on the Sent state.
## Manual verification
- **Real POST /v1/auth/password-reset against a running server** — Vitest only mocks `useApi`;
confirm the real 200/429/500 round-trip (including the actual rate limiter and Retry-After
header) against `task dev` with a live SQLite file. The endpoint's own contract is already
covered by `features/request_password_reset.qa.md`; this slice only re-verifies the screen
consumes it correctly.
- **429 countdown drift** — confirm `useRetryAfter`'s live countdown does not drift against a
real elapsed 58-second wait, since Vitest fake timers only prove the logic.