6.1 KiB
6.1 KiB
QA: Pending registration screen
Automated (Vitest + Vue Test Utils, task test:web)
Mock useApi (DELETE /v1/auth/register, POST /v1/auth/logout) and useToast/useOverlay per
case; no real backend, no httptest server. Mount PendingPage inside AuthShell with a test router and
a test Pinia session store. Seed/clear sessionStorage["renewcms:pendingEmail"] per case.
- Default state — set
sessionStorage["renewcms:pendingEmail"] = "marta@renew.example"; mount at /register/pending; assert a ResultPanel with tone "success", icon "i-lucide-mail-check", title "Check your email", text "We sent a verification link to marta@renew.example. It expires in 2 hours.", the note paragraph rendered via the default slot, and two secondary actions "Log out" and "Cancel registration". - Email unknown state — clear
sessionStorage["renewcms:pendingEmail"]; mount at /register/pending; assert the same ResultPanel shape with text "We sent a verification link to the email you registered with. It expires in 2 hours." and the same note and actions. - Logging out — mount with an unresolved
POST /v1/auth/logoutmock; click "Log out"; assert both actions are disabled; resolve the mock 200; assert the session store'sclear()was called and the router's current path is /login. - Confirm cancel opens the dialog — click "Cancel registration"; assert a ConfirmDialog renders
with title "Cancel your registration?", description "Your account will be deleted. You can
register again with the same or a different email.", buttons "Keep my account" and "Cancel
registration" (tone danger),
role="alertdialog", and initial focus on "Keep my account". - Cancelling state — with the dialog open, mock
DELETE /v1/auth/registerwith an unresolved promise, click "Cancel registration" inside the dialog; assert both dialog buttons are disabled, the confirm button reads "Cancelling…",aria-busy="true"on the dialog, and the mocked call was made with{ onForbidden: 'passthrough' }. - Keep my account — with the dialog open, click "Keep my account"; assert the dialog closes,
DELETE /v1/auth/registerwas never called, and the underlying ResultPanel is unchanged. - Cancelled state — confirm the dialog; mock
DELETE /v1/auth/registerresolving 200; assert the dialog closes, the router's current path is /register, and a toast was raised with color "success", icon "i-lucide-circle-check", title "Registration cancelled", description "You can create the owner account again." - Already verified state — seed the session store with
{ verified: false },status:'ready'; confirm the dialog; mockDELETE /v1/auth/registerresolving 403; mock the session store'sretry()to resolve and setsession.session = { verified: true }; assertretry()was awaited before the navigation; assert the "You're verified" ResultPanel ("Taking you to your dashboard…", no actions) is shown and a toast was raised with color "info", icon "i-lucide-info", title "Your account is already verified", description "There's nothing to cancel." while the path is not yet /home; then assert the router reaches /home after 800 ms with no second toast. - Cancel failed state — two sub-cases: (a) a 500 response, (b) a rejected fetch. In each, confirm the dialog, resolve/reject the mock accordingly, and assert the dialog stays open, an inline failure indicator is shown inside it (not a toast — assert no toast was raised), and both dialog buttons are re-enabled.
useApionForbidden option (unit-level, alongside the existing suite inapi_client_global_error_handling's spec file) — seedsession = { verified: false }; mock fetch resolving 403; calluseApi().request('/v1/auth/register', { method: 'DELETE', onForbidden: 'passthrough' }); assert the promise rejects withApiErrorstatus 403; assert the router's current route did not change (no redirect to /register/pending); assert the session store is unchanged. This regresses nothing in the existing onForbidden-absent (default 'redirect') scenarios already covered byfeatures/api_client_global_error_handling.feature.
Visual (manual verification — desktop and mobile, light and dark)
Reference: docs/design/source/RenewCMS Screens Auth.dc.html, group "Pending". Run
task visual:check -- pending for each state and compare against the board frame.
- Default state: icon tile, title, text with the interpolated email, note paragraph, "Log out" and "Cancel registration" secondary buttons — matches the board exactly.
- Email unknown state: same layout with the generic text.
- Confirm cancel state: ConfirmDialog layout, button order (Keep my account left, Cancel registration right, danger color), matches components.md's button-order rule.
- Cancelling state: disabled buttons, "Cancelling…" label, spinner/aria-busy styling.
- Cancelled state (transient, capture via visual test hook or a frozen mock): toast appearance over the /register board.
- Already verified state: the "You're verified" ResultPanel with the info toast over it,
captured before the 800 ms redirect (the visual setup freezes timers with
paused: true). - Keyboard/focus: focus starts on "Keep my account" in the dialog and Enter does not confirm; while cancelling, focus cannot leave the dialog; on the ResultPanel states, focus lands on the title on mount; toasts are announced without stealing focus.
Manual verification
- Real DELETE /v1/auth/register and POST /v1/auth/logout against a running server — Vitest only
mocks
useApi; confirm the real 200/403 round-trips againsttask devwith a live SQLite file. The endpoint's own status/body/cookie contract is already covered byfeatures/cancel_pending_registration.qa.md; this slice only re-verifies the screen consumes it correctly. - Router-guard staleness fix in a real browser — confirm that after the "Already verified" 403,
a hard reload of /home does not bounce back to /register/pending, since Vitest's fake session store
can't fully reproduce the router's
afterEachre-check timing.