3.8 KiB
3.8 KiB
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.
- 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.
- Validation error state — set Email to "marta@renew", submit; assert the mocked
POST /v1/auth/password-resetwas never called; assert the error "Enter a full email address, like name@example.com." - 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.
- 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.
- 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. - 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) orrole="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) againsttask devwith a live SQLite file. The endpoint's own contract is already covered byfeatures/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.