From be2259ceecc3b9d76864a0a75a6d02298b49d56d Mon Sep 17 00:00:00 2001 From: waterlemonnn Date: Sun, 9 Aug 2026 02:34:35 +0700 Subject: [PATCH] test(search): cover short-query early return and result path Newsletter route already has coverage from #68 (new/existing/ reactivated subscriber cases). This adds the missing search half: queries under 2 chars short-circuit without hitting the DB, and a normal query passes agent/severity filters through to fetchSearchPosts. --- app/api/search/route.test.ts | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 app/api/search/route.test.ts diff --git a/app/api/search/route.test.ts b/app/api/search/route.test.ts new file mode 100644 index 0000000..a449a03 --- /dev/null +++ b/app/api/search/route.test.ts @@ -0,0 +1,70 @@ +import { NextRequest } from "next/server"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const fetchSearchPosts = vi.fn(); + +vi.mock("@/lib/db/posts", () => ({ + fetchSearchPosts, +})); + +function createRequest(query: string) { + return new NextRequest(`http://localhost/api/search?${query}`); +} + +describe("GET /api/search", () => { + beforeEach(() => { + vi.resetModules(); + vi.clearAllMocks(); + }); + + it("returns an empty result without querying for a too-short query", async () => { + const { GET } = await import("./route"); + const response = await GET(createRequest("q=a")); + + expect(response.status).toBe(200); + await expect(response.json()).resolves.toEqual({ posts: [] }); + expect(fetchSearchPosts).not.toHaveBeenCalled(); + }); + + it("returns an empty result for a missing query", async () => { + const { GET } = await import("./route"); + const response = await GET(createRequest("")); + + await expect(response.json()).resolves.toEqual({ posts: [] }); + expect(fetchSearchPosts).not.toHaveBeenCalled(); + }); + + it("searches and returns posts for a normal query", async () => { + fetchSearchPosts.mockResolvedValue([ + { id: "post-1", title: "Agent deleted a database" }, + ]); + + const { GET } = await import("./route"); + const response = await GET(createRequest("q=database")); + + expect(response.status).toBe(200); + expect(fetchSearchPosts).toHaveBeenCalledWith("database", { + agentSlug: undefined, + minSeverity: undefined, + maxSeverity: undefined, + }); + await expect(response.json()).resolves.toEqual({ + posts: [{ id: "post-1", title: "Agent deleted a database" }], + }); + }); + + it("passes through agent and severity filters", async () => { + fetchSearchPosts.mockResolvedValue([]); + + const { GET } = await import("./route"); + await GET( + createRequest("q=outage&agent=claude&minSeverity=2&maxSeverity=4"), + ); + + expect(fetchSearchPosts).toHaveBeenCalledWith("outage", { + agentSlug: "claude", + minSeverity: 2, + maxSeverity: 4, + }); + }); +});