Files
RenewCMS/features/unverified_users_and_reregistration.qa.md

3.6 KiB

QA procedure: unverified_users_and_reregistration

Package: test (black-box), extending test/user_test.go (mockUserRepo) and reusing the openInMemoryDb(t) helper from test/not_found_errors_test.go.

Setup shared by every case

  1. Call validator.InitValidator() once.
  2. Repository-level checks use openInMemoryDb(t), db.AutoMigrate(&models.User{}), and a real persistence.NewUserRepository(db).
  3. HTTP-level checks use mockUserRepo (from test/user_test.go) wired into useCases.NewCreateUserUseCase(repo, &hashing.BcryptHasher{}), useCases.NewListUsersUseCase(repo), useCases.NewGetUserUseCase(repo), useCases.NewAuthenticateUserUseCase(repo, ...), and auth.NewHandler(...) with a test jwtauth.New("HS256", []byte("test-secret"), nil). Mount POST /v1/auth/register and POST /v1/auth/login unprotected on a fresh chi.NewRouter(), mirroring api/router.go. No live server.

Repository-level checks (real persistence repository, in-memory SQLite, no HTTP)

  1. On an empty repository, Create a user "alice"/"alice@example.com" with PasswordResetCode: "" and VerificationCode: "code-alice" → assert err == nil. Create a second user "bob"/"bob@example.com" with PasswordResetCode: "" and VerificationCode: "code-bob" → assert err == nil (regression: before the fix this fails with a SQLite UNIQUE constraint failed: users.password_reset_code error). Then GetByUsername("alice") and GetByUsername("bob") → assert PasswordResetCode == "" for both.
  2. Create a user "alice" with PasswordResetCode: "shared-code". Create a user "bob" with the same PasswordResetCode: "shared-code" → assert err != nil (the unique constraint still applies to an actual shared value). Assert GetByUsername("bob") returns user.ErrUserNotFound (the row was never created).
  3. Create a user "alice"/"alice@example.com", capture its id. Delete(id) → assert err == nil. Create a new user with the same username "alice" and email "alice@example.com" (a different password and verification code) → assert err == nil (regression: before the fix this fails with a SQLite UNIQUE constraint failed: users.username error because the row was only soft-deleted). Assert the new user's id differs from the deleted one. Assert Get(deletedId) returns user.ErrUserNotFound.
  4. Create a user "alice"/"alice@example.com" and do not delete it. Create a second user with username "alice" and a different email → assert err != nil (unchanged: still rejected while the row is live).

HTTP checks (fakes, per the shared setup above)

  1. POST /v1/auth/register with {"username":"alice","password":"hunter2example12","email":"alice@example.com"} against an empty mockUserRepo → assert status 200, a Set-Cookie: jwt=... header present, body decodes to {"message":"User registered! HTTPonly jwt cookie created"}.
  2. POST /v1/auth/register again with {"username":"bob","password":"hunter2example12","email":"bob@example.com"} (repo now holds unverified "alice") → assert status 200 and a Set-Cookie: jwt=... header present (register stays allowed because no user is verified yet).
  3. Assert mockUserRepo.users holds two entries, both IsVerified == false and both PasswordResetCode == "".

Manual verification (not exercised by the Go test)

  • None. DeleteUser has no HTTP route mounted today, so there is no SPA-visible delete-and-re-register flow to check by hand, and CreateUser does not call the mailer, so there is no SMTP involvement in this slice.