Skip to main content
Glama
alexander-zuev

Kollektiv | Your private LLM knowledgebase

login.test.ts6.49 kB
/** * Unit-tests for the login handler. * * Behaviour covered * ───────────────── * • Form-data parsing * • Happy paths for GitHub / Google / Magic-link * • Basic error handling * • Misc helpers (single parseBody call, redirectTo computation) */ import {loginHandler} from "@/web/handlers/login"; import {AppRoutes} from "@/web/routes"; import {LoginProvider} from "@/web/templates"; import type {Context} from "hono"; import {beforeEach, describe, expect, it, vi, Mock} from "vitest"; import {getSupabase} from "@/web/middleware/supabase"; const TEST_EMAIL = "test@user.com"; const TEST_TX = "unit-test-tx"; vi.mock("@/web/templates", async () => { // We still want all the real exports except the ones we override const actual = await vi.importActual<object>("@/web/templates"); return { ...actual, // Stub the render helper so we can assert against it renderMagicLinkSentScreen: vi .fn() .mockResolvedValue("<div id='magic-link-sent'>Email sent 🚀</div>"), // A tiny base() impl so the handler can wrap the HTML base: (content: string, _title: string) => `<html><body>${content}</body></html>`, }; }); describe("Login Handler tests covering all major flows", () => { // Provided by the unit.setup.ts let c!: Context; beforeEach((ctx) => { c = ctx.c as Context; /* Inject the tx query parameter for every test */ vi.spyOn(c.req, "query").mockImplementation((key?: string) => key === "tx" ? TEST_TX : undefined, ); }); it("Redirects to Github provider URL on success", async () => { const supabase = getSupabase(c); (supabase.auth.signInWithOAuth as Mock).mockResolvedValue({ data: {url: "https://github.com/oauth"}, error: null, }); c.req.parseBody = vi.fn().mockResolvedValueOnce({provider: LoginProvider.GITHUB}); const res = await loginHandler(c); expect(supabase.auth.signInWithOAuth).toHaveBeenCalledWith({ provider: LoginProvider.GITHUB, options: expect.objectContaining({ redirectTo: `${c.env.SITE_URL}${AppRoutes.AUTH_CALLBACK}?tx=${TEST_TX}`, }), }); expect(res.status).toBe(302); expect(res.headers.get("location")).toBe("https://github.com/oauth"); }); it("Redirects to Google provider URL on success", async () => { const supabase = getSupabase(c); (supabase.auth.signInWithOAuth as Mock).mockResolvedValue({ data: {url: "https://google.com/oauth"}, error: null, }); c.req.parseBody = vi.fn().mockResolvedValueOnce({ provider: LoginProvider.GOOGLE, }); const res = await loginHandler(c); expect(supabase.auth.signInWithOAuth).toHaveBeenCalledWith({ provider: LoginProvider.GOOGLE, options: expect.objectContaining({ redirectTo: `${c.env.SITE_URL}${AppRoutes.AUTH_CALLBACK}?tx=${TEST_TX}`, }), }); expect(res.status).toBe(302); expect(res.headers.get("location")).toBe("https://google.com/oauth"); }); it("Renders check your email screen on success", async () => { const supabase = getSupabase(c); (supabase.auth.signInWithOtp as Mock).mockResolvedValue({ data: { user: null, session: null, }, error: null, }); c.req.parseBody = vi.fn().mockResolvedValueOnce({ provider: LoginProvider.MAGIC_LINK, email: TEST_EMAIL, }); const res = await loginHandler(c); expect(supabase.auth.signInWithOtp).toHaveBeenCalledWith({ email: TEST_EMAIL, options: expect.objectContaining({ shouldCreateUser: true, emailRedirectTo: `${c.env.SITE_URL}${AppRoutes.AUTH_CALLBACK}?tx=${TEST_TX}`, }), }); /* ---------- HTML rendering ---------- */ const templates = await import("@/web/templates"); expect(templates.renderMagicLinkSentScreen).toHaveBeenCalledWith({ email: TEST_EMAIL, }); expect(res.headers.get("content-type")).toMatch(/text\/html/); const html = await res.text(); expect(html).toContain("magic-link-sent"); }); describe.each([ ["GitHub", LoginProvider.GITHUB, "Kaboom!"], ["Google", LoginProvider.GOOGLE, "Kaboom!"], ])("Test error handling for provider - %s", (providerName, provider, errMsg) => { let c!: Context; beforeEach((ctx) => { c = ctx.c as Context; }); it(`Returns 500 text response when ${providerName} auth fails`, async () => { const supabase = getSupabase(c); (supabase.auth.signInWithOAuth as Mock).mockResolvedValue({ data: null, error: {message: `${errMsg}`}, }); c.req.parseBody = vi.fn().mockResolvedValueOnce({provider: `${provider}`}); const res = (await loginHandler(c)) as any; expect(supabase.auth.signInWithOAuth).toHaveBeenCalledWith({ provider: provider, options: expect.objectContaining({ redirectTo: `${c.env.SITE_URL}${AppRoutes.AUTH_CALLBACK}?tx=${TEST_TX}`, }), }); expect(res.status).toBe(500); expect(await res.text()).toContain(`Error logging in with ${providerName}: ${errMsg}`); }); }); describe("misc", () => { it("parses formData exactly once", async () => { // Arrange c.req.parseBody = vi.fn().mockResolvedValueOnce({provider: "github"}); const supabase = getSupabase(c); (supabase.auth.signInWithOAuth as Mock).mockResolvedValue({ data: {url: "https://github.com/oauth"}, error: null, }); // Act await loginHandler(c); // Assert expect(c.req.parseBody).toHaveBeenCalledTimes(1); // extra sanity-check: the provider that was read is the one we passed on expect(supabase.auth.signInWithOAuth).toHaveBeenCalledWith( expect.objectContaining({provider: "github"}), ); }); }); });

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