86 lines
5.0 KiB
Gherkin
86 lines
5.0 KiB
Gherkin
Feature: Password reset request screen
|
|
|
|
As a RenewCMS user who forgot their password
|
|
I want a /register/reset/request screen that emails a reset link via POST
|
|
/v1/auth/password-reset, validates the email client-side before sending, and never reveals
|
|
whether the address has an account
|
|
So that I can ask for a reset link with the same neutral confirmation regardless of whether my
|
|
account exists, and see plainly when I'm asking too often or the server failed
|
|
|
|
Background:
|
|
Given /register/reset/request is a public route (meta.auth "public") rendered as
|
|
ResetRequestPage inside AuthShell, per docs/design/routes.md
|
|
And ResetRequestPage only calls POST /v1/auth/password-reset
|
|
And the form has a single Email field (placeholder "you@example.com")
|
|
And client-side validation runs on submit only, before any request is sent: Email must be a
|
|
well-formed email address (the same pattern RegisterPage already uses), and a failing Email
|
|
shows "Enter a full email address, like name@example.com."
|
|
And a valid submit calls POST /v1/auth/password-reset with { email }
|
|
And every response the API gives — whether the email belongs to an account or not — is the
|
|
same 200 with the same body, per features/request_password_reset.feature, so the screen
|
|
shows the same Sent state either way
|
|
And a 429 response carries a Retry-After header in seconds, surfaced by useApi and displayed
|
|
as a live countdown on the submit button, the same mechanism LoginPage's own 429 handling
|
|
uses, and the Email field is disabled for the same duration
|
|
And a 500 response, or a request that never reaches the server, is surfaced as a
|
|
server/network error; the field keeps whatever the user typed and the form re-enables
|
|
And a 400 response is not expected once client-side validation passes, since the client
|
|
checks the same required,email rule the API enforces; it is out of scope for this slice
|
|
|
|
Scenario: Default — a fresh, empty form
|
|
When the user navigates to /register/reset/request
|
|
Then the heading is "Reset your password"
|
|
And the description is "Enter the email for your account and we'll send you a link to choose
|
|
a new password."
|
|
And the Email field shows placeholder "you@example.com" with no value
|
|
And the submit button reads "Send reset link"
|
|
And the footer reads "Back to log in" linking to /login
|
|
|
|
Scenario: Validation error — an invalid email blocks the request
|
|
Given the user is on /register/reset/request
|
|
When the user types "marta@renew" into Email and submits
|
|
Then POST /v1/auth/password-reset is never called
|
|
And the Email field shows the error "Enter a full email address, like name@example.com."
|
|
|
|
Scenario: Submitting — the field and button are disabled while the request is in flight
|
|
Given the user is on /register/reset/request with Email "marta@renew.example"
|
|
When the user submits and POST /v1/auth/password-reset has not yet resolved
|
|
Then the Email field is disabled
|
|
And the submit button reads "Sending…" and shows a loading state
|
|
|
|
Scenario: Sent — any 200 shows the same neutral confirmation
|
|
Given the user is on /register/reset/request with Email "marta@renew.example"
|
|
When the user submits and POST /v1/auth/password-reset resolves 200
|
|
Then the form is replaced by a ResultPanel with tone "success", icon "i-lucide-mail-check",
|
|
title "Check your email", text "If an account exists for that email, a password reset link
|
|
has been sent.", and note "The link expires in 1 hour."
|
|
And its single action is a secondary "Back to log in"
|
|
When the user activates "Back to log in"
|
|
Then the app navigates to /login
|
|
|
|
Scenario: Too many attempts — the button is disabled with a live countdown
|
|
Given the user is on /register/reset/request with Email "marta@renew.example"
|
|
When the user submits and POST /v1/auth/password-reset resolves 429 with a Retry-After of 58
|
|
seconds
|
|
Then an info alert reads "Too many requests" with description "Wait a moment before asking
|
|
for another link."
|
|
And the Email field still shows "marta@renew.example"
|
|
And the submit button reads "Try again in 0:58" and is disabled
|
|
And the Email field is disabled while the countdown runs
|
|
When 58 seconds elapse
|
|
Then the submit button re-enables and reads "Send reset link"
|
|
And the Email field is editable again
|
|
|
|
Scenario Outline: Server or network error — the field keeps its value and re-enables
|
|
Given the user is on /register/reset/request with Email "marta@renew.example"
|
|
When the user submits and POST /v1/auth/password-reset <failure>
|
|
Then an error alert reads "Couldn't send the link" with description "Check your connection
|
|
and try again."
|
|
And the Email field still shows "marta@renew.example" and is re-enabled
|
|
And the submit button reads "Send reset link" again, no longer loading
|
|
|
|
Examples:
|
|
| failure |
|
|
| fails with a 500 response |
|
|
| never reaches the server |
|