Files
RenewCMS/features/cancel_pending_registration.qa.md

5.0 KiB

QA procedure: cancel_pending_registration

Package: test (black-box), extending test/user_test.go (mockUserRepo) and following the router/handler wiring pattern already used in test/account_verification_http_test.go.

Test infrastructure reused, none new needed

mockUserRepo already supports deleting an entry (used by the existing DeleteUserUseCase tests in test/use_case_baseline_test.go) and returning user.ErrUserNotFound from Get once a user is gone. No new mock methods are required; CancelRegistrationUseCase only calls Get and Delete, both of which mockUserRepo already implements.

Setup shared by every case

  1. Call validator.InitValidator() once.
  2. Use-case-level checks build useCases.NewCancelRegistrationUseCase(repo) where repo is a mockUserRepo pre-populated directly via repo.users[id] = user.User{...}.
  3. HTTP-level checks wire mockUserRepo, useCases.NewCancelRegistrationUseCase(repo) and the other existing use cases into auth.NewHandler(...) (extended with the new CancelRegistrationUseCase parameter) with a test jwtauth.New("HS256", []byte("test-secret"), nil). Mount DELETE /v1/auth/register on a fresh chi.NewRouter() wrapped in jwtauth.Verifier(token) then jwtauth.Authenticator(token), mirroring the protected group api/router.go adds inside NewAuthRouter (the same group POST /v1/auth/verify already sits in). Mint jwt cookies with token.Encode(map[string]any{"user_id": uint32(7)}) for the valid-token cases.

Use-case-level checks (no HTTP)

  1. Repo has user id 3, IsVerified: false. Call CancelRegistration(3). Assert err == nil. Assert repo.users no longer has key 3 (or repo.Get(3) returns user.ErrUserNotFound).
  2. Repo has user id 3, IsVerified: true. Call CancelRegistration(3). Assert errors.Is(err, user.ErrAlreadyVerified). Assert the repo still has user id 3 with IsVerified: true.
  3. Repo has no user with id 42. Call CancelRegistration(42). Assert errors.Is(err, user.ErrUserNotFound).

HTTP-level checks (fakes, per the shared setup above)

  1. Seed mockUserRepo with user id 7, username "alice", email "alice@example.com", IsVerified: false. Mint a valid jwt cookie for user id 7. DELETE /v1/auth/register with that cookie → assert status 200, response body decodes to a JSON object with a message field, the response has a Set-Cookie header for jwt with MaxAge < 0 (or an Expires in the past) and an empty Value (parse with http.ParseSetCookie, mirroring secureAttributeFromResponse in test/runtime_settings_injection_http_test.go), and repo.Get(7) now returns user.ErrUserNotFound.
  2. Re-registration after cancel: repeat case 7's cancel call on the same router/repo, then POST /v1/auth/register with {"username":"alice","password":"hunter2example12","email":"alice@example.com"} → assert status 200, a jwt Set-Cookie header is present with a non-empty value, and the newly created user's id (read back via repo.GetByUsername("alice") or the use case) is different from 7.
  3. Seed mockUserRepo with user id 7, username "alice", email "alice@example.com", IsVerified: true. Mint a valid jwt cookie for user id 7. DELETE /v1/auth/register with that cookie → assert status 403, body exactly the apperr.AlreadyVerifiedErrorMessage constant, no Set-Cookie header for jwt is present in the response, and repo.Get(7) still returns the user with IsVerified: true.
  4. Table-driven over three "no valid user_id" cases, each against a fresh seed of user id 7, IsVerified: false, and asserting status 401, a response body equal to apperr.UnauthorizedErrorMessage, no jwt Set-Cookie header in the response, and repo.Get(7) still succeeding afterward:
    • mint the jwt with token.Encode(map[string]any{"role": "user"}) (no user_id key at all);
    • mint the jwt with token.Encode(map[string]any{"user_id": "seven"}) (string, not a number);
    • mint the jwt with token.Encode(map[string]any{"user_id": uint32(999)}) (well-formed but no such user in the repo).
  5. A request with no jwt cookie at all against the same router → assert status 401 (produced by jwtauth.Authenticator itself, before the handler runs); do not assert an exact body for this case, and assert repo.Get(7) still succeeds afterward.

Manual verification (not exercised by the Go test)

  • The SPA-visible "cancel registration" affordance (wherever it is surfaced to a logged-in, unverified user, e.g. on the pending-verification screen) actually calling DELETE /v1/auth/register and redirecting to a logged-out state on success is out of scope for this slice's automated test and should be checked by hand against a running dev build.
  • End-to-end confirmation against the real SQLite file that the row is physically gone (not just hidden by a soft-delete) is already covered at the repository level by features/unverified_users_and_reregistration.feature and is not re-verified here.