From e73596ca79e72ce3f2345badaa15feb031d651fb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:22:58 +0000 Subject: [PATCH] Add tests for Auth Logout handler --- apps/server/go.mod | 2 +- .../internal/modules/auth/handler_test.go | 90 +++++++++++++------ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/apps/server/go.mod b/apps/server/go.mod index f8d76d9..0c09ae6 100644 --- a/apps/server/go.mod +++ b/apps/server/go.mod @@ -1,6 +1,6 @@ module github.com/coderz-space/coderz.space -go 1.24.3 +go 1.25.0 require ( github.com/go-playground/validator/v10 v10.30.1 diff --git a/apps/server/internal/modules/auth/handler_test.go b/apps/server/internal/modules/auth/handler_test.go index d250365..5b89fcd 100644 --- a/apps/server/internal/modules/auth/handler_test.go +++ b/apps/server/internal/modules/auth/handler_test.go @@ -1,6 +1,11 @@ package auth import ( + "strings" + "net/http" + "net/http/httptest" + + "github.com/labstack/echo/v5" "testing" ) @@ -347,30 +352,42 @@ func TestRefreshResponseStructure(t *testing.T) { // // Requirements: 0.7 func TestLogoutTokenRevocation(t *testing.T) { - tests := []struct { - name string - scenario string - }{ - { - name: "logout with refresh token deletes token", - scenario: "refresh_token cookie present", - }, - { - name: "logout without refresh token succeeds", - scenario: "no refresh_token cookie", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // This test documents that Logout: - // - Deletes refresh token from database if present - // - Clears access_token and refresh_token cookies (MaxAge=-1) - // - Always returns success (idempotent) - // - Returns HTTP 200 status - t.Logf("Scenario: %s", tt.scenario) - }) - } + t.Run("logout without refresh token clears cookies", func(t *testing.T) { + e := echo.New() + req := httptest.NewRequest(http.MethodPost, "/v1/auth/logout", nil) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + h := &Handler{} // No service needed when no refresh_token cookie exists + + err := h.Logout(c) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if rec.Code != http.StatusOK { + t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code) + } + + cookies := rec.Result().Cookies() + accessCleared := false + refreshCleared := false + for _, cookie := range cookies { + if cookie.Name == "access_token" && cookie.MaxAge == -1 { + accessCleared = true + } + if cookie.Name == "refresh_token" && cookie.MaxAge == -1 { + refreshCleared = true + } + } + + if !accessCleared { + t.Error("access_token cookie was not cleared") + } + if !refreshCleared { + t.Error("refresh_token cookie was not cleared") + } + }) } // TestLogoutResponseStructure verifies response format @@ -378,11 +395,26 @@ func TestLogoutTokenRevocation(t *testing.T) { // Requirements: 0.7 func TestLogoutResponseStructure(t *testing.T) { t.Run("response indicates success", func(t *testing.T) { - // This test documents that Logout returns: - // - success: true - // - data: {} (empty object) - // - HTTP 200 status - t.Log("Response follows GenericResponse structure") + e := echo.New() + req := httptest.NewRequest(http.MethodPost, "/v1/auth/logout", nil) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + h := &Handler{} // No service needed when no refresh_token cookie exists + + err := h.Logout(c) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if rec.Code != http.StatusOK { + t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code) + } + + body := rec.Body.String() + if !strings.Contains(body, "\"success\":true") { + t.Errorf("expected response to contain success:true, got %s", body) + } }) }