diff --git a/src/app/api/tags/popular/route.test.ts b/src/app/api/tags/popular/route.test.ts new file mode 100644 index 00000000..2fadf27f --- /dev/null +++ b/src/app/api/tags/popular/route.test.ts @@ -0,0 +1,73 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { NextRequest } from "next/server"; +import { GET } from "./route"; + +const mockFrom = vi.fn(); + +const supabaseClient = { + from: mockFrom, +}; + +vi.mock("@/lib/supabase/server", () => ({ + createClient: vi.fn(() => Promise.resolve(supabaseClient)), +})); + +function makeRequest(limit: string) { + return new NextRequest(`http://localhost/api/tags/popular?limit=${limit}`); +} + +function setupTags(count: number) { + const gigs = { + select: vi.fn().mockReturnValue({ + eq: vi.fn().mockResolvedValue({ + data: Array.from({ length: count }, (_, index) => ({ + skills_required: [`tag-${index}`], + })), + error: null, + }), + }), + }; + const follows = { + select: vi.fn().mockResolvedValue({ data: [], error: null }), + }; + + mockFrom.mockImplementation((table: string) => + table === "gigs" ? gigs : follows + ); +} + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe("GET /api/tags/popular", () => { + it("clamps zero limits to one tag", async () => { + setupTags(3); + + const response = await GET(makeRequest("0")); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.tags).toHaveLength(1); + }); + + it("falls back from malformed limits", async () => { + setupTags(55); + + const response = await GET(makeRequest("abc")); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.tags).toHaveLength(50); + }); + + it("caps oversized limits", async () => { + setupTags(205); + + const response = await GET(makeRequest("999")); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.tags).toHaveLength(200); + }); +}); diff --git a/src/app/api/tags/popular/route.ts b/src/app/api/tags/popular/route.ts index 9536c769..3c79b4ea 100644 --- a/src/app/api/tags/popular/route.ts +++ b/src/app/api/tags/popular/route.ts @@ -1,14 +1,12 @@ import { NextRequest, NextResponse } from "next/server"; import { createClient } from "@/lib/supabase/server"; +import { parsePaginationParam } from "@/lib/api-pagination"; // GET /api/tags/popular — list popular tags with gig and follower counts export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams; - const limit = Math.min( - Math.max(parseInt(searchParams.get("limit") || "50", 10) || 50, 1), - 200 - ); + const limit = parsePaginationParam(searchParams.get("limit"), 50, 1, 200); const supabase = await createClient();