Files
RenewCMS/features/registration_status_endpoint.qa.md
T

59 lines
3.8 KiB
Markdown

# QA procedure: registration_status_endpoint
Package: `test` (black-box), extending `test/user_test.go` (`mockUserRepo`, `stubHasher`) and
`test/mail_test.go` (`mockMailRepo`), and following the router wiring pattern in
`test/registration_gate_and_verification_email_http_test.go` /
`test/get_current_user_http_test.go`.
## Setup shared by every case
1. Call `validator.InitValidator()` once.
2. Build `createUserUseCase := useCases.NewCreateUserUseCase(repo, &stubHasher{}, mailRepo,
"https://cms.example.com")` where `repo` is a `mockUserRepo` and `mailRepo` is a `mockMailRepo`.
3. Build the auth handler(s) the same way `NewAuthRouter` does, but only mount what each case needs:
`GET /v1/auth/registration` unprotected, at the router's top level (no `jwtauth.Verifier`, no
`jwtauth.Authenticator`, no `middleware.NewRateLimiter`), on a fresh `chi.NewRouter()`. No live
server, no real SQLite file, no real SMTP.
## HTTP-level checks
4. Empty `mockUserRepo`. `GET /v1/auth/registration` with no cookie → assert status `200`,
`Cache-Control` header equals `"no-store"`, and the decoded JSON body is exactly `{"open": true}`
(assert there is no other top-level key by decoding into `map[string]any` and checking `len(body)
== 1`).
5. `mockUserRepo` seeded with one user, `IsVerified: false`. `GET /v1/auth/registration` → assert
status `200` and body exactly `{"open": true}`.
6. `mockUserRepo` seeded with one user, `IsVerified: true`. `GET /v1/auth/registration` → assert
status `200`, `Cache-Control: no-store`, and body exactly `{"open": false}`.
7. Same seed as step 6. Attach a jwt cookie whose value is invalid/expired/garbage — e.g. a plain
string like `"jwt=not-a-real-token"`, or a token minted with a different signing key, or one built
with `token.Encode` and then manually expired/truncated — deliberately NOT a cookie freshly minted
with `token.Encode` against the router's own signing key. `GET /v1/auth/registration` with that
cookie attached → assert status `200`, body exactly `{"open": false}` (identical to step 6's
cookie-less result), and no `Set-Cookie` header on the response. This demonstrates the route never
parses or validates the cookie at all, since an invalid/expired one produces byte-identical output
to no cookie.
8. `mockUserRepo` seeded with three users (two `IsVerified: true`, one `IsVerified: false`).
`GET /v1/auth/registration` → decode the body into `map[string]any`, assert its only key is
`"open"`, and assert the raw response body (as a string) does not contain any of the seeded
usernames or emails, and does not contain a numeric user count anywhere but inside the boolean
`open` value.
9. Empty `mockUserRepo`. Send `GET /v1/auth/registration` 20 times in a row against the same
router/repo (a plain loop of `httptest.NewRequest` + `ServeHTTP`, no external rate limiter
middleware mounted on this route) → assert every response status is `200` and none is `429`.
## Use-case-level check (no HTTP)
10. Build a `user.Repository` fake (`mockUserRepo`) containing one user with `IsVerified: true`. Build
`CreateUserUseCase` over that fake, a `stubHasher`, and a `mockMailRepo`. Call the new exported
method (e.g. `IsRegistrationOpen()`) and assert it returns `false`. Then call `CreateUser` with a
new username/email/password on the same use case instance and assert
`errors.Is(err, user.ErrRegistrationClosed)` — proving both entry points consult the same
underlying check rather than two independently-maintained copies.
## Manual verification (not exercised by the Go test)
- The SPA actually calling `GET /v1/auth/registration` before rendering the registration form (rather
than always showing it and relying on the 403 from POST /v1/auth/register) is out of scope for this
slice's automated test and should be checked by hand against a running dev build.