Files
RenewCMS/features/accept_invite_screen.feature
T

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