import { beforeEach, describe, expect, mock, test } from "bun:test"; const fetchFacebookItems = mock( (): Promise< | { title: string }[] | { results: { title: string }[]; unstableResults: { title: string }[] } > => Promise.resolve([{ title: "item" }]), ); const fetchEbayItems = mock( (): Promise< | { title: string }[] | { results: { title: string }[]; unstableResults: { title: string }[] } > => Promise.resolve([{ title: "item" }]), ); const fetchKijijiItems = mock( (): Promise< | { title: string }[] | { results: { title: string }[]; unstableResults: { title: string }[] } > => Promise.resolve([{ title: "item" }]), ); mock.module("@marketplace-scrapers/core", () => ({ fetchFacebookItems, fetchEbayItems, fetchKijijiItems, })); describe("API routes", () => { beforeEach(() => { fetchFacebookItems.mockReset(); fetchFacebookItems.mockImplementation( () => Promise.resolve([{ title: "item" }]) as Promise<{ title: string }[]>, ); fetchEbayItems.mockReset(); fetchEbayItems.mockImplementation( () => Promise.resolve([{ title: "item" }]) as Promise<{ title: string }[]>, ); fetchKijijiItems.mockReset(); fetchKijijiItems.mockImplementation( () => Promise.resolve([{ title: "item" }]) as Promise<{ title: string }[]>, ); }); test("facebookRoute ignores cookies query parameter", async () => { const { facebookRoute } = await import("../src/routes/facebook"); await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3&cookies=c_user=1", ), ); expect(fetchFacebookItems).toHaveBeenCalledWith("laptop", 1, "toronto", 3); }); test("ebayRoute ignores cookies query parameter", async () => { const { ebayRoute } = await import("../src/routes/ebay"); await ebayRoute( new Request( "http://localhost/api/ebay?q=laptop&cookies=s%3D1&buyItNowOnly=true", ), ); expect(fetchEbayItems).toHaveBeenCalledWith("laptop", 1, { minPrice: undefined, maxPrice: undefined, strictMode: false, exclusions: [], keywords: ["laptop"], buyItNowOnly: true, canadaOnly: true, }); }); test("kijijiRoute ignores cookies query parameter", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); await kijijiRoute( new Request( "http://localhost/api/kijiji?q=laptop&cookies=s%3D1&maxPages=3", ), ); expect(fetchKijijiItems).toHaveBeenCalledWith( "laptop", 4, "https://www.kijiji.ca", { location: undefined, category: undefined, keywords: undefined, sortBy: undefined, sortOrder: undefined, maxPages: 3, priceMin: undefined, priceMax: undefined, }, {}, ); }); test("facebookRoute forwards unstableFilter=true to core", async () => { const { facebookRoute } = await import("../src/routes/facebook"); fetchFacebookItems.mockImplementation(() => Promise.resolve({ results: [{ title: "item" }], unstableResults: [], }), ); await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3&unstableFilter=true", ), ); expect(fetchFacebookItems).toHaveBeenCalledWith("laptop", 1, "toronto", 3, { hideUnstableResults: true, }); }); test("ebayRoute forwards unstableFilter=true to core", async () => { const { ebayRoute } = await import("../src/routes/ebay"); fetchEbayItems.mockImplementation(() => Promise.resolve({ results: [{ title: "item" }], unstableResults: [], }), ); await ebayRoute( new Request( "http://localhost/api/ebay?q=laptop&buyItNowOnly=true&unstableFilter=true", ), ); expect(fetchEbayItems).toHaveBeenCalledWith( "laptop", 1, { minPrice: undefined, maxPrice: undefined, strictMode: false, exclusions: [], keywords: ["laptop"], buyItNowOnly: true, canadaOnly: true, }, { hideUnstableResults: true, }, ); }); test("kijijiRoute forwards unstableFilter=true to core", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); fetchKijijiItems.mockImplementation(() => Promise.resolve({ results: [{ title: "item" }], unstableResults: [], }), ); await kijijiRoute( new Request( "http://localhost/api/kijiji?q=laptop&maxPages=5&unstableFilter=true", ), ); expect(fetchKijijiItems).toHaveBeenCalledWith( "laptop", 4, "https://www.kijiji.ca", { location: undefined, category: undefined, keywords: undefined, sortBy: undefined, sortOrder: undefined, maxPages: 5, priceMin: undefined, priceMax: undefined, }, {}, { hideUnstableResults: true, }, ); }); test("facebookRoute does not forward unstableFilter when absent", async () => { const { facebookRoute } = await import("../src/routes/facebook"); await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3", ), ); expect(fetchFacebookItems).toHaveBeenCalledWith("laptop", 1, "toronto", 3); }); test("facebookRoute does not forward unstableFilter when false", async () => { const { facebookRoute } = await import("../src/routes/facebook"); await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3&unstableFilter=false", ), ); expect(fetchFacebookItems).toHaveBeenCalledWith("laptop", 1, "toronto", 3); }); test("ebayRoute does not forward unstableFilter when absent", async () => { const { ebayRoute } = await import("../src/routes/ebay"); await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&buyItNowOnly=true"), ); expect(fetchEbayItems).toHaveBeenCalledWith("laptop", 1, { minPrice: undefined, maxPrice: undefined, strictMode: false, exclusions: [], keywords: ["laptop"], buyItNowOnly: true, canadaOnly: true, }); }); test("ebayRoute does not forward unstableFilter when false", async () => { const { ebayRoute } = await import("../src/routes/ebay"); await ebayRoute( new Request( "http://localhost/api/ebay?q=laptop&buyItNowOnly=true&unstableFilter=false", ), ); expect(fetchEbayItems).toHaveBeenCalledWith("laptop", 1, { minPrice: undefined, maxPrice: undefined, strictMode: false, exclusions: [], keywords: ["laptop"], buyItNowOnly: true, canadaOnly: true, }); }); test("kijijiRoute does not forward unstableFilter when absent", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=5"), ); expect(fetchKijijiItems).toHaveBeenCalledWith( "laptop", 4, "https://www.kijiji.ca", { location: undefined, category: undefined, keywords: undefined, sortBy: undefined, sortOrder: undefined, maxPages: 5, priceMin: undefined, priceMax: undefined, }, {}, ); }); test("kijijiRoute does not forward unstableFilter when false", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); await kijijiRoute( new Request( "http://localhost/api/kijiji?q=laptop&maxPages=5&unstableFilter=false", ), ); expect(fetchKijijiItems).toHaveBeenCalledWith( "laptop", 4, "https://www.kijiji.ca", { location: undefined, category: undefined, keywords: undefined, sortBy: undefined, sortOrder: undefined, maxPages: 5, priceMin: undefined, priceMax: undefined, }, {}, ); }); test("facebookRoute returns bucket shape when unstableFilter is enabled", async () => { const { facebookRoute } = await import("../src/routes/facebook"); fetchFacebookItems.mockImplementation(() => Promise.resolve({ results: [{ title: "a" }], unstableResults: [{ title: "b" }], }), ); const response = await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3&unstableFilter=true", ), ); const body = await response.json(); expect(body.results).toHaveLength(1); expect(body.unstableResults).toHaveLength(1); expect(body.results[0].title).toBe("a"); expect(body.unstableResults[0].title).toBe("b"); }); test("kijijiRoute returns bucket shape when unstableFilter is enabled", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); fetchKijijiItems.mockImplementation(() => Promise.resolve({ results: [{ title: "a" }], unstableResults: [{ title: "b" }], }), ); const response = await kijijiRoute( new Request( "http://localhost/api/kijiji?q=laptop&maxPages=5&unstableFilter=true", ), ); const body = await response.json(); expect(body.results).toHaveLength(1); expect(body.unstableResults).toHaveLength(1); expect(body.results[0].title).toBe("a"); expect(body.unstableResults[0].title).toBe("b"); }); test("facebookRoute returns 404 when unstable results are empty", async () => { const { facebookRoute } = await import("../src/routes/facebook"); fetchFacebookItems.mockImplementation(() => Promise.resolve({ results: [], unstableResults: [], }), ); const response = await facebookRoute( new Request( "http://localhost/api/facebook?q=laptop&location=toronto&maxItems=3&unstableFilter=true", ), ); expect(response.status).toBe(404); const body = await response.json(); expect(body.message).toBe("Search didn't return any results!"); }); test("kijijiRoute returns 404 when unstable results are empty", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); fetchKijijiItems.mockImplementation(() => Promise.resolve({ results: [], unstableResults: [], }), ); const response = await kijijiRoute( new Request( "http://localhost/api/kijiji?q=laptop&maxPages=5&unstableFilter=true", ), ); expect(response.status).toBe(404); const body = await response.json(); expect(body.message).toStartWith("Search didn't return any results!"); expect(body.message).toContain("Kijiji matches ALL words"); }); test("ebayRoute forwards maxItems to core in default mode", async () => { const { ebayRoute } = await import("../src/routes/ebay"); fetchEbayItems.mockImplementation(() => Promise.resolve([{ title: "a" }])); await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=2"), ); expect(fetchEbayItems).toHaveBeenCalledWith( "laptop", 1, expect.objectContaining({ maxItems: 2 }), ); }); test("ebayRoute passes through scraper payload unchanged in unstable mode", async () => { const { ebayRoute } = await import("../src/routes/ebay"); fetchEbayItems.mockImplementation(() => Promise.resolve({ results: [{ title: "a" }, { title: "b" }, { title: "c" }], unstableResults: [{ title: "d" }, { title: "e" }], }), ); const response = await ebayRoute( new Request( "http://localhost/api/ebay?q=laptop&unstableFilter=true&maxItems=4", ), ); const body = await response.json(); expect(body.results).toHaveLength(3); expect(body.unstableResults).toHaveLength(2); expect(body.results[0].title).toBe("a"); expect(body.unstableResults[0].title).toBe("d"); expect(fetchEbayItems).toHaveBeenCalledWith( "laptop", 1, expect.objectContaining({ maxItems: 4 }), { hideUnstableResults: true, }, ); }); test("ebayRoute forwards maxItems to core in unstable mode", async () => { const { ebayRoute } = await import("../src/routes/ebay"); fetchEbayItems.mockImplementation(() => Promise.resolve({ results: [{ title: "a" }], unstableResults: [{ title: "b" }], }), ); await ebayRoute( new Request( "http://localhost/api/ebay?q=laptop&unstableFilter=true&maxItems=2", ), ); expect(fetchEbayItems).toHaveBeenCalledWith( "laptop", 1, expect.objectContaining({ maxItems: 2 }), { hideUnstableResults: true, }, ); }); test("ebayRoute returns 404 when unstable results are empty", async () => { const { ebayRoute } = await import("../src/routes/ebay"); fetchEbayItems.mockImplementation(() => Promise.resolve({ results: [], unstableResults: [], }), ); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&unstableFilter=true"), ); expect(response.status).toBe(404); const body = await response.json(); expect(body.message).toBe("Search didn't return any results!"); }); test("ebayRoute returns 400 for invalid maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for non-integer maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for decimal maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for empty maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for whitespace maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for hex maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for invalid maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for non-integer maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for decimal maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for empty maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for whitespace maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("facebookRoute returns 400 for hex maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for empty minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for whitespace minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for hex minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for empty maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("ebayRoute returns 400 for whitespace maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("ebayRoute returns 400 for hex maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("ebayRoute returns 400 for non-integer minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for invalid minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for decimal minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for non-integer maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("ebayRoute returns 400 for invalid maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("ebayRoute returns 400 for decimal maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("kijijiRoute returns 400 for decimal maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for invalid maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for non-integer maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for empty maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for whitespace maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for hex maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for invalid priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for decimal priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for non-integer priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for empty priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for whitespace priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for hex priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for invalid priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("kijijiRoute returns 400 for decimal priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=1.5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("kijijiRoute returns 400 for non-integer priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=10abc"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("kijijiRoute returns 400 for empty priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax="), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("kijijiRoute returns 400 for whitespace priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=%20%20"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("kijijiRoute returns 400 for hex priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=0x10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); test("facebookRoute returns 400 for negative maxItems", async () => { const { facebookRoute } = await import("../src/routes/facebook"); const response = await facebookRoute( new Request("http://localhost/api/facebook?q=laptop&maxItems=-1"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for negative maxItems", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxItems=-1"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxItems parameter"); }); test("ebayRoute returns 400 for negative minPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&minPrice=-5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid minPrice parameter"); }); test("ebayRoute returns 400 for negative maxPrice", async () => { const { ebayRoute } = await import("../src/routes/ebay"); const response = await ebayRoute( new Request("http://localhost/api/ebay?q=laptop&maxPrice=-10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPrice parameter"); }); test("kijijiRoute returns 400 for negative maxPages", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&maxPages=-2"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid maxPages parameter"); }); test("kijijiRoute returns 400 for negative priceMin", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMin=-5"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMin parameter"); }); test("kijijiRoute returns 400 for negative priceMax", async () => { const { kijijiRoute } = await import("../src/routes/kijiji"); const response = await kijijiRoute( new Request("http://localhost/api/kijiji?q=laptop&priceMax=-10"), ); expect(response.status).toBe(400); const body = await response.json(); expect(body.message).toBe("Invalid priceMax parameter"); }); });