/* @vitest-environment node */ import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn(), })); vi.mock("@/lib/search", () => ({ search: vi.fn(), })); import { getSession } from "@/lib/auth/session"; import { search as searchBackend } from "@/lib/search"; import { GET, dynamic } from "./route.js"; describe("GET /api/search", () => { beforeEach(() => { vi.clearAllMocks(); }); it('exports dynamic="force-dynamic"', () => { expect(dynamic).toBe("force-dynamic"); }); it("returns 401 when unauthenticated", async () => { getSession.mockResolvedValue(null); const req = new Request("http://localhost/api/search?q=test&branch=NL01"); const res = await GET(req); expect(res.status).toBe(401); expect(await res.json()).toEqual({ error: { message: "Unauthorized", code: "AUTH_UNAUTHENTICATED" }, }); }); it("returns 403 when branch user tries to access a different branch", async () => { getSession.mockResolvedValue({ userId: "u1", role: "branch", branchId: "NL01", }); const req = new Request("http://localhost/api/search?q=test&branch=NL02"); const res = await GET(req); expect(res.status).toBe(403); expect(await res.json()).toEqual({ error: { message: "Forbidden", code: "AUTH_FORBIDDEN_BRANCH" }, }); }); it("returns 400 when missing both q and date range", async () => { getSession.mockResolvedValue({ userId: "u2", role: "admin", branchId: null, }); const req = new Request("http://localhost/api/search?branch=NL01"); const res = await GET(req); expect(res.status).toBe(400); expect(await res.json()).toMatchObject({ error: { code: "VALIDATION_SEARCH_MISSING_FILTER", }, }); }); it("returns 400 for invalid date format", async () => { getSession.mockResolvedValue({ userId: "u2", role: "admin", branchId: null, }); const req = new Request( "http://localhost/api/search?branch=NL01&q=x&from=2025/01/01" ); const res = await GET(req); expect(res.status).toBe(400); expect(await res.json()).toMatchObject({ error: { code: "VALIDATION_SEARCH_DATE", }, }); }); it("returns 200 and passes through items + nextCursor", async () => { getSession.mockResolvedValue({ userId: "u2", role: "admin", branchId: null, }); searchBackend.mockResolvedValue({ items: [ { branch: "NL20", date: "2025-12-18", year: "2025", month: "12", day: "18", filename: "x.pdf", relativePath: "NL20/2025/12/18/x.pdf", }, ], nextCursor: "abc", total: 1, }); const req = new Request( "http://localhost/api/search?branch=NL20&q=bridgestone&limit=100" ); const res = await GET(req); expect(res.status).toBe(200); expect(await res.json()).toEqual({ items: [ { branch: "NL20", date: "2025-12-18", year: "2025", month: "12", day: "18", filename: "x.pdf", relativePath: "NL20/2025/12/18/x.pdf", }, ], nextCursor: "abc", total: 1, }); expect(searchBackend).toHaveBeenCalledTimes(1); }); });