//go:build test // +build test package user import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "crussell/db" "crussell/mw" "crussell/testutils/fixtures" "crussell/testutils/jwt" "crussell/testutils/testdb" "github.com/jackc/pgx/v5/pgxpool" ) func setupTest(t *testing.T) (func(), *pgxpool.Pool) { pool := testdb.Pool(t) testdb.Migrate(t, pool) testdb.TruncateTables(t, pool) // Set the global DB pool db.DB = pool // Initialize JWT jwt.Init() return func() { pool.Close() }, pool } func TestProfile_Get(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } token := jwt.GenerateUserToken(userID) req := httptest.NewRequest(http.MethodGet, "/api/user/profile", nil) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) rr := httptest.NewRecorder() GetProfileHandler(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) t.Logf("response body: %s", rr.Body.String()) } var profile UserProfile if err := json.Unmarshal(rr.Body.Bytes(), &profile); err != nil { t.Fatalf("failed to unmarshal response: %v", err) } if profile.ID != userID { t.Errorf("expected user ID %s, got %s", userID, profile.ID) } } func TestProfile_Get_NoAuth(t *testing.T) { cleanup, _ := setupTest(t) defer cleanup() req := httptest.NewRequest(http.MethodGet, "/api/user/profile", nil) rr := httptest.NewRecorder() GetProfileHandler(rr, req) if rr.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d", rr.Code) } } func TestProfile_Update(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } token := jwt.GenerateUserToken(userID) updateReq := UpdateProfileRequest{ FirstName: "John", LastName: "Doe", Phone: "07123456789", } body, _ := json.Marshal(updateReq) req := httptest.NewRequest(http.MethodPut, "/api/user/profile", bytes.NewReader(body)) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() UpdateProfileHandler(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) t.Logf("response body: %s", rr.Body.String()) } } func TestPasswordChange_Success(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } token := jwt.GenerateUserToken(userID) changeReq := ChangePasswordRequest{ CurrentPassword: "testpassword123", NewPassword: "newpassword456", } body, _ := json.Marshal(changeReq) req := httptest.NewRequest(http.MethodPut, "/api/user/change-password", bytes.NewReader(body)) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() ChangePasswordHandler(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) t.Logf("response body: %s", rr.Body.String()) } } func TestPasswordChange_WrongOld(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } token := jwt.GenerateUserToken(userID) changeReq := ChangePasswordRequest{ CurrentPassword: "wrongpassword", NewPassword: "newpassword456", } body, _ := json.Marshal(changeReq) req := httptest.NewRequest(http.MethodPut, "/api/user/change-password", bytes.NewReader(body)) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() ChangePasswordHandler(rr, req) if rr.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d", rr.Code) } } func TestAccount_Delete(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } token := jwt.GenerateUserToken(userID) req := httptest.NewRequest(http.MethodDelete, "/api/user/account", nil) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) rr := httptest.NewRecorder() DeleteAccountHandler(rr, req) if rr.Code != http.StatusNoContent { t.Errorf("expected status 204, got %d", rr.Code) t.Logf("response body: %s", rr.Body.String()) } } func TestLoyalty_Get(t *testing.T) { cleanup, pool := setupTest(t) defer cleanup() userID, err := fixtures.CreateTestUser(pool) if err != nil { t.Fatalf("failed to create test user: %v", err) } // Add some loyalty stamps _, err = pool.Exec(context.Background(), `UPDATE users SET loyalty_stamps = 10 WHERE id = $1`, userID) if err != nil { t.Fatalf("failed to update loyalty stamps: %v", err) } token := jwt.GenerateUserToken(userID) req := httptest.NewRequest(http.MethodGet, "/api/user/loyalty", nil) req = req.WithContext(context.WithValue(context.Background(), mw.UserIDKey, userID)) req.Header.Set("Authorization", "Bearer "+token) rr := httptest.NewRecorder() GetLoyaltyHandler(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) t.Logf("response body: %s", rr.Body.String()) } var loyalty LoyaltyResponse if err := json.Unmarshal(rr.Body.Bytes(), &loyalty); err != nil { t.Fatalf("failed to unmarshal response: %v", err) } if loyalty.Stamps != 10 { t.Errorf("expected 10 stamps, got %d", loyalty.Stamps) } if loyalty.ReferralCode == "" { t.Error("expected referral code to be set") } }