# 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) 4. 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`). 5. 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`. 6. 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) 7. 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`. 8. 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`. 9. 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`. 10. 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). 11. 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.