import { describe, expect, test } from "bun:test"; import type { RuntimeMode } from "../../src/shared/api"; import { parseListParams } from "../../src/server/helpers/list-params"; const mode: RuntimeMode = "test"; function makeUrl(params: Record = {}): URL { const sp = new URLSearchParams(params); return new URL(`http://localhost/api/test?${sp.toString()}`); } describe("parseListParams", () => { test("returns defaults when no params provided", () => { const url = makeUrl(); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.page).toBe(1); expect(result.pageSize).toBe(20); expect(result.keyword).toBeUndefined(); expect(result.sortBy).toBeUndefined(); expect(result.sortOrder).toBeUndefined(); }); test("parses valid pagination params", () => { const url = makeUrl({ page: "2", pageSize: "50" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.page).toBe(2); expect(result.pageSize).toBe(50); }); test("parses keyword param", () => { const url = makeUrl({ keyword: "test" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.keyword).toBe("test"); }); test("keyword empty string becomes undefined", () => { const url = makeUrl({ keyword: "" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.keyword).toBeUndefined(); }); test("parses valid sort params", () => { const url = makeUrl({ sortBy: "name", sortOrder: "asc" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.sortBy).toBe("name"); expect(result.sortOrder).toBe("asc"); }); test("parses desc sortOrder", () => { const url = makeUrl({ sortBy: "createdAt", sortOrder: "desc" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.sortOrder).toBe("desc"); }); test("sortBy without sortOrder returns undefined sortOrder", () => { const url = makeUrl({ sortBy: "name" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.sortBy).toBe("name"); expect(result.sortOrder).toBeUndefined(); }); test("rejects invalid page", () => { const url = makeUrl({ page: "0" }); const result = parseListParams(url, mode); expect(result).toBeInstanceOf(Response); expect((result as Response).status).toBe(400); }); test("rejects negative page", () => { const url = makeUrl({ page: "-1" }); const result = parseListParams(url, mode); expect(result).toBeInstanceOf(Response); }); test("rejects non-integer page", () => { const url = makeUrl({ page: "1.5" }); const result = parseListParams(url, mode); expect(result).toBeInstanceOf(Response); }); test("rejects pageSize over 200", () => { const url = makeUrl({ pageSize: "201" }); const result = parseListParams(url, mode); expect(result).toBeInstanceOf(Response); }); test("rejects invalid sortOrder", () => { const url = makeUrl({ sortBy: "name", sortOrder: "invalid" }); const result = parseListParams(url, mode); expect(result).toBeInstanceOf(Response); }); test("rejects sortBy not in whitelist", () => { const url = makeUrl({ sortBy: "evil" }); const result = parseListParams(url, mode, { allowedSortBy: ["name", "createdAt"] }); expect(result).toBeInstanceOf(Response); }); test("allows sortBy in whitelist", () => { const url = makeUrl({ sortBy: "name" }); const result = parseListParams(url, mode, { allowedSortBy: ["name", "createdAt"] }); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.sortBy).toBe("name"); }); test("allows sortBy when no whitelist provided", () => { const url = makeUrl({ sortBy: "anything" }); const result = parseListParams(url, mode); if (result instanceof Response) throw new Error("Should not return Response"); expect(result.sortBy).toBe("anything"); }); test("parses all params together", () => { const url = makeUrl({ keyword: "hello", page: "3", pageSize: "10", sortBy: "createdAt", sortOrder: "desc" }); const result = parseListParams(url, mode, { allowedSortBy: ["createdAt"] }); if (result instanceof Response) throw new Error("Should not return Response"); expect(result).toEqual({ keyword: "hello", page: 3, pageSize: 10, sortBy: "createdAt", sortOrder: "desc", }); }); });