Skip to main content
Glama
alexander-zuev

Kollektiv | Your private LLM knowledgebase

authContext.test.ts8.81 kB
import { AuthFlowError, getValidAuthContext, isValidOAuthRequest } from "@/web/utils/authContext"; import { loadAuthCookie, saveAuthCookie } from "@/web/utils/cookies"; import type { Context } from "hono"; import { deleteCookie } from "hono/cookie"; import { type Mock, beforeEach, describe, expect, it, vi } from "vitest"; // Mock the cookies module vi.mock("@/web/utils/cookies", () => ({ loadAuthCookie: vi.fn(), saveAuthCookie: vi.fn(), })); // Mock the hono/cookie module vi.mock("hono/cookie", () => ({ deleteCookie: vi.fn(), })); describe("Auth Context Utilities", () => { // Reset mocks before each test beforeEach(() => { vi.resetAllMocks(); }); describe("AuthFlowError", () => { it("should create an error with the correct name and message", () => { const error = new AuthFlowError("Test error message"); expect(error.name).toBe("AuthFlowError"); expect(error.message).toBe("Test error message"); }); }); describe("isValidOAuthRequest", () => { it("should return true for valid OAuth request", () => { const validRequest = { clientId: "test-client-id", redirectUri: "https://example.com/callback", }; expect(isValidOAuthRequest(validRequest)).toBe(true); }); it("should return false for null or undefined", () => { expect(isValidOAuthRequest(null)).toBe(false); expect(isValidOAuthRequest(undefined)).toBe(false); }); it("should return false for request without clientId", () => { const invalidRequest = { redirectUri: "https://example.com/callback" }; expect(isValidOAuthRequest(invalidRequest)).toBe(false); }); it("should return false for request with empty clientId", () => { const invalidRequest = { clientId: "", redirectUri: "https://example.com/callback" }; expect(isValidOAuthRequest(invalidRequest)).toBe(false); }); }); describe("getValidAuthContext", () => { // Create a mock context for testing const createMockContext = (txParam?: string): Context => { const url = txParam ? `https://example.com?tx=${txParam}` : "https://example.com"; return { req: { raw: new Request(url), url: url, }, env: { OAUTH_PROVIDER: { parseAuthRequest: vi.fn(), lookupClient: vi.fn(), }, SITE_URL: "https://example.com", }, } as unknown as Context; }; // Test transaction ID const TEST_TX = "test-transaction-id"; // Valid test data const validOAuthReq = { clientId: "test-client-id", redirectUri: "https://example.com/callback", }; const validClientInfo = { clientName: "Test Client" }; const validCsrfToken = "test-csrf-token"; it("should return valid context from request parameters", async () => { // Arrange const mockContext = createMockContext(); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue(validOAuthReq); mockContext.env.OAUTH_PROVIDER.lookupClient.mockResolvedValue(validClientInfo); // Mock crypto.randomUUID to return predictable values const originalRandomUUID = crypto.randomUUID; crypto.randomUUID = vi .fn() .mockReturnValueOnce(TEST_TX) // First call for tx .mockReturnValueOnce(validCsrfToken); // Second call for csrfToken // Act const result = await getValidAuthContext(mockContext); // Assert expect(result).toEqual({ oauthReq: validOAuthReq, client: validClientInfo, tx: TEST_TX, csrfToken: validCsrfToken, }); expect(saveAuthCookie).toHaveBeenCalledWith(mockContext, TEST_TX, { oauthReq: validOAuthReq, csrfToken: validCsrfToken, }); expect(mockContext.env.OAUTH_PROVIDER.parseAuthRequest).toHaveBeenCalledWith( mockContext.req.raw, ); expect(mockContext.env.OAUTH_PROVIDER.lookupClient).toHaveBeenCalledWith( validOAuthReq.clientId, ); // Restore original function crypto.randomUUID = originalRandomUUID; }); it("should fall back to cookie when AuthRequest is invalid in a subsequent request", async () => { // Arrange const mockContext = createMockContext(TEST_TX); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue({ clientId: "" }); // Invalid OAuth request mockContext.env.OAUTH_PROVIDER.lookupClient.mockResolvedValue(validClientInfo); const cookieData = { oauthReq: validOAuthReq, csrfToken: validCsrfToken, }; (loadAuthCookie as Mock).mockResolvedValue(cookieData); // Act const result = await getValidAuthContext(mockContext); // Assert expect(result).toEqual({ oauthReq: validOAuthReq, client: validClientInfo, tx: TEST_TX, csrfToken: validCsrfToken, }); expect(saveAuthCookie).not.toHaveBeenCalled(); expect(loadAuthCookie).toHaveBeenCalledWith(mockContext, TEST_TX); }); it("should throw AuthFlowError when parameters are invalid in the first request", async () => { // Arrange const mockContext = createMockContext(); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue({ clientId: "" }); // Invalid OAuth request // Mock loadAuthCookie to return null to ensure it's treated as a first request (loadAuthCookie as Mock).mockResolvedValue(null); // Mock crypto.randomUUID to return predictable values const originalRandomUUID = crypto.randomUUID; crypto.randomUUID = vi.fn().mockReturnValue(TEST_TX); // Act & Assert await expect(getValidAuthContext(mockContext)).rejects.toThrow(AuthFlowError); // Restore original function crypto.randomUUID = originalRandomUUID; }); it("should handle errors from parseAuthRequest in a subsequent request", async () => { // Arrange const mockContext = createMockContext(TEST_TX); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockRejectedValue(new Error("Parse error")); const cookieData = { oauthReq: validOAuthReq, csrfToken: validCsrfToken, }; (loadAuthCookie as Mock).mockResolvedValue(cookieData); mockContext.env.OAUTH_PROVIDER.lookupClient.mockResolvedValue(validClientInfo); // Act const result = await getValidAuthContext(mockContext); // Assert expect(result).toEqual({ oauthReq: validOAuthReq, client: validClientInfo, tx: TEST_TX, csrfToken: validCsrfToken, }); expect(saveAuthCookie).not.toHaveBeenCalled(); }); it("throws AuthFlowError when client lookup fails in the first request", async () => { // Arrange const mockContext = createMockContext(); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue(validOAuthReq); // Mock loadAuthCookie to return null to ensure it's treated as a first request (loadAuthCookie as Mock).mockResolvedValue(null); // Mock client lookup to throw an AuthFlowError mockContext.env.OAUTH_PROVIDER.lookupClient.mockRejectedValue( new AuthFlowError("Client lookup failed"), ); // Mock crypto.randomUUID to return predictable values const originalRandomUUID = crypto.randomUUID; crypto.randomUUID = vi .fn() .mockReturnValueOnce(TEST_TX) // First call for tx .mockReturnValueOnce(validCsrfToken); // Second call for csrfToken // ─ Act & Assert await expect(getValidAuthContext(mockContext)).rejects.toThrow(AuthFlowError); // Restore original function crypto.randomUUID = originalRandomUUID; }); describe("cookie with missing client info", () => { it("should throw AuthFlowError when cookie exists but client lookup fails", async () => { // Arrange const mockContext = createMockContext(TEST_TX); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue({ clientId: "" }); // Invalid OAuth request const cookieData = { oauthReq: validOAuthReq, csrfToken: validCsrfToken, }; (loadAuthCookie as Mock).mockResolvedValue(cookieData); // Mock client lookup to fail with an AuthFlowError mockContext.env.OAUTH_PROVIDER.lookupClient.mockRejectedValue( new AuthFlowError("Client lookup failed"), ); // ─ Act & Assert await expect(getValidAuthContext(mockContext)).rejects.toThrow(AuthFlowError); expect(loadAuthCookie).toHaveBeenCalledWith(mockContext, TEST_TX); }); it("should throw AuthFlowError when client is not found", async () => { // Arrange const mockContext = createMockContext(TEST_TX); mockContext.env.OAUTH_PROVIDER.parseAuthRequest.mockResolvedValue({ clientId: "" }); // Invalid OAuth request const cookieData = { oauthReq: validOAuthReq, csrfToken: validCsrfToken, }; (loadAuthCookie as Mock).mockResolvedValue(cookieData); // Mock client lookup to return null mockContext.env.OAUTH_PROVIDER.lookupClient.mockResolvedValue(null); // ─ Act & Assert await expect(getValidAuthContext(mockContext)).rejects.toThrow(AuthFlowError); expect(loadAuthCookie).toHaveBeenCalledWith(mockContext, TEST_TX); }); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alexander-zuev/kollektiv-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server