106 lines
5.7 KiB
Gherkin
106 lines
5.7 KiB
Gherkin
Feature: Accept invite screen
|
|
|
|
As a person who opened the link in the invitation email
|
|
I want /invite/accept?c=CODE to show me the invited address and let me choose a username and
|
|
password
|
|
So that I finish setting up my account and arrive logged in
|
|
|
|
Background:
|
|
Given /invite/accept is a public route (meta.auth "public") rendered as AcceptInvitePage inside
|
|
AuthShell, per docs/design/routes.md
|
|
And on mount AcceptInvitePage reads the "c" query parameter once: if it is absent or empty no
|
|
request is made and the "Invalid or used link (404)" state renders
|
|
And otherwise it calls GET /v1/auth/invite?c=CODE and shows "Checking the link" until it resolves
|
|
And the Username and Password rules are Register's, including PasswordStrengthHint, with no
|
|
confirm field; validation runs on blur and on submit and nothing is sent when it fails
|
|
And a submit that passes calls POST /v1/auth/invite/accept with { code: c, username, password }
|
|
And a logged-in visitor sees the same screen: the route stays public and nothing redirects
|
|
And the board is docs/design/source/RenewCMS Screens Auth.dc.html, group "Accept invite"; the
|
|
board frame decides layout and sample data (lea.martin@renew.example, "lea", "limewash2026",
|
|
"marta")
|
|
|
|
Scenario: Checking the link
|
|
When the user opens /invite/accept?c=abc123 and GET /v1/auth/invite has not resolved
|
|
Then a full-card spinner reads "Checking your invite…"
|
|
|
|
Scenario: Default
|
|
Given GET /v1/auth/invite?c=abc123 resolves 200 with {"email": "lea.martin@renew.example"}
|
|
Then the heading is "Accept your invite"
|
|
And the description is "Choose a username and password to finish setting up your account."
|
|
And the Email field has placeholder "you@example.com", shows "lea.martin@renew.example", is
|
|
read-only, with help "From your invitation."
|
|
And the Username field has placeholder "e.g. lea", counter "0 / 20" and help "Letters and numbers,
|
|
3 to 20 characters. You'll use it to log in."
|
|
And the Password field is a password input with show/hide and checklist "At least 8 characters" unmet
|
|
And the submit button reads "Accept invite"
|
|
And the footer reads "Already have an account?" with a "Log in" link to /login
|
|
|
|
Scenario: Validation errors
|
|
Given the form is shown, Username is "ma" and Password is "lime"
|
|
When the user blurs both fields and submits
|
|
Then POST /v1/auth/invite/accept is never called
|
|
And the Username shows counter "2 / 20" in error and the error "Use 3 to 20 characters."
|
|
And the checklist item "At least 8 characters" is in its error state
|
|
|
|
Scenario: Filled, valid
|
|
Given Username is "lea" and Password is "limewash2026" with the password shown
|
|
Then the counter reads "3 / 20", the checklist item "At least 8 characters" is met and no error shows
|
|
|
|
Scenario: Submitting
|
|
When the user submits valid values and POST /v1/auth/invite/accept has not resolved
|
|
Then the fields and button are disabled
|
|
And the submit button reads "Creating account…" and is loading
|
|
|
|
Scenario: Username taken (409)
|
|
When POST /v1/auth/invite/accept resolves 409 with body "That username is taken. Try another."
|
|
Then the Username keeps "marta", shows counter "5 / 20", is focused and shows the error
|
|
"That username is taken. Try another."
|
|
And the Password keeps its value, the form re-enables and the button reads "Accept invite"
|
|
|
|
Scenario Outline: The link does not work
|
|
When <trigger>
|
|
Then no form is shown
|
|
And a ResultPanel (tone error, icon i-lucide-link-2-off) reads "This invite link doesn't work"
|
|
with text "It may be incomplete, or it may already have been used. If you already set up your
|
|
account, log in instead." and note "Open the link from your email again, or copy the full
|
|
address into your browser."
|
|
And its only action is a primary "Go to log in" that navigates to /login
|
|
|
|
Examples:
|
|
| trigger |
|
|
| the user opens /invite/accept with no c parameter (no request is made) |
|
|
| GET /v1/auth/invite?c=abc123 resolves 404 |
|
|
| the submit resolves 404, replacing the form |
|
|
| the submit resolves 409 with apperr.EmailHasAccountErrorMessage |
|
|
|
|
Scenario Outline: Expired link (410)
|
|
When <trigger>
|
|
Then no form is shown
|
|
And a ResultPanel (tone error, icon i-lucide-clock) reads "This invite has expired" with text
|
|
"Invites work once, for 3 days. Ask the person who invited you to send a new one."
|
|
And its only action is a secondary "Go to log in" that navigates to /login
|
|
|
|
Examples:
|
|
| trigger |
|
|
| GET /v1/auth/invite?c=abc123 resolves 410 |
|
|
| the submit resolves 410, replacing the form |
|
|
|
|
Scenario Outline: Server error
|
|
When the submit <failure>
|
|
Then an error Alert (icon i-lucide-circle-x) reads "Couldn't create the account" with "Something
|
|
went wrong on the server. Try again in a moment." above the heading
|
|
And the form is still shown with Email, Username "lea" and Password "limewash2026" kept, re-enabled
|
|
|
|
Examples:
|
|
| failure |
|
|
| resolves 500 |
|
|
| resolves 429 |
|
|
| never reaches the server |
|
|
|
|
Scenario: Success
|
|
When POST /v1/auth/invite/accept resolves 200 with the jwt cookie
|
|
Then a ResultPanel (tone success, icon i-lucide-circle-check) reads "Your account is ready" with
|
|
text "Taking you to your dashboard…"
|
|
And a Toast (icon i-lucide-circle-check) reads "Welcome to RenewCMS" with "You're logged in as lea."
|
|
And after 800 ms the app navigates to /home with no verification step
|