import { NextRequest } from "next/server"; import { beforeEach, describe, expect, it, vi } from "vitest"; const isDatabaseConfiguredMock = vi.fn(); const getSessionPepperMock = vi.fn(); const hashSessionTokenMock = vi.fn(); const findUniqueMock = vi.fn(); const deleteMock = vi.fn(); const upsertMock = vi.fn(); const createSessionForUserMock = vi.fn(); const setSessionCookieMock = vi.fn(); vi.mock("../../lib/server/env", () => ({ isDatabaseConfigured: () => isDatabaseConfiguredMock(), getSessionPepper: () => getSessionPepperMock(), })); vi.mock("../../lib/server/hash", () => ({ hashSessionToken: (...args: unknown[]) => hashSessionTokenMock(...args), })); vi.mock("../../lib/server/session", () => ({ createSessionForUser: (...args: unknown[]) => createSessionForUserMock(...args), setSessionCookie: (...args: unknown[]) => setSessionCookieMock(...args), })); vi.mock("../../lib/server/db", () => ({ prisma: { magicLinkToken: { findUnique: (...args: unknown[]) => findUniqueMock(...args), delete: (...args: unknown[]) => deleteMock(...args), }, user: { upsert: (...args: unknown[]) => upsertMock(...args), }, }, })); import { GET } from "../../app/api/auth/magic-link/verify/route"; beforeEach(() => { isDatabaseConfiguredMock.mockReset(); getSessionPepperMock.mockReset(); hashSessionTokenMock.mockReset(); findUniqueMock.mockReset(); deleteMock.mockReset(); upsertMock.mockReset(); createSessionForUserMock.mockReset(); setSessionCookieMock.mockReset(); isDatabaseConfiguredMock.mockReturnValue(true); getSessionPepperMock.mockReturnValue("pepper"); hashSessionTokenMock.mockReturnValue("token-hash"); }); function getWithToken(token: string) { return new NextRequest( `https://x.test/api/auth/magic-link/verify?token=${encodeURIComponent(token)}`, ); } describe("GET /api/auth/magic-link/verify", () => { it("redirects with invalid_link when the token is missing", async () => { const res = await GET( new NextRequest("https://x.test/api/auth/magic-link/verify"), ); expect(res.status).toBe(307); expect(res.headers.get("location")).toContain("error=invalid_link"); }); it("redirects with invalid_link when no row matches", async () => { findUniqueMock.mockResolvedValue(null); const res = await GET(getWithToken("a-token-value-long-enough")); expect(res.status).toBe(307); expect(res.headers.get("location")).toContain("error=invalid_link"); }); it("redirects with expired_link when the row is past expiresAt", async () => { findUniqueMock.mockResolvedValue({ id: "row-1", email: "a@b.c", expiresAt: new Date(Date.now() - 1000), nextPath: null, draftPayload: null, }); const res = await GET(getWithToken("a-token-value-long-enough")); expect(res.status).toBe(307); expect(res.headers.get("location")).toContain("error=expired_link"); }); });