package handler import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gofiber/fiber/v2" ) // helper to build a Fiber app with the handler route mounted. func newTestApp(h *AuthHandler) *fiber.App { app := fiber.New() app.Post("/api/v1/auth/password/reset/complete", h.CompletePasswordReset) return app } func TestCompletePasswordReset_MissingLoginID(t *testing.T) { h := &AuthHandler{} app := newTestApp(h) body, _ := json.Marshal(map[string]string{ "newPassword": "Password1!", }) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/reset/complete", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { t.Fatalf("expected 400 for missing loginId, got %d", resp.StatusCode) } var got map[string]string if err := json.NewDecoder(resp.Body).Decode(&got); err != nil { t.Fatalf("failed to decode response: %v", err) } if got["error"] != "Login ID and new password are required" { t.Fatalf("unexpected error message: %v", got["error"]) } } func TestCompletePasswordReset_InvalidPasswordPolicy(t *testing.T) { h := &AuthHandler{} app := newTestApp(h) body, _ := json.Marshal(map[string]string{ "newPassword": "short", // too short + missing complexity }) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/reset/complete?loginId=user@example.com", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusBadRequest { t.Fatalf("expected 400 for weak password, got %d", resp.StatusCode) } var got map[string]string if err := json.NewDecoder(resp.Body).Decode(&got); err != nil { t.Fatalf("failed to decode response: %v", err) } if got["error"] != "Password must be at least 8 characters long" { t.Fatalf("unexpected error message: %v", got["error"]) } } func TestCompletePasswordReset_NilDescopeClient(t *testing.T) { h := &AuthHandler{} // DescopeClient intentionally nil to hit the configuration error branch app := newTestApp(h) body, _ := json.Marshal(map[string]string{ "newPassword": "StrongPass1!", }) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/password/reset/complete?loginId=user@example.com", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) if err != nil { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusInternalServerError { t.Fatalf("expected 500 when Descope client is nil, got %d", resp.StatusCode) } var got map[string]string if err := json.NewDecoder(resp.Body).Decode(&got); err != nil { t.Fatalf("failed to decode response: %v", err) } if got["error"] != "Authentication service not configured" { t.Fatalf("unexpected error message: %v", got["error"]) } }