From 25f590247c956806bf9207d3c7db685cbf8bc60f Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 10 Apr 2026 11:02:28 +0200 Subject: [PATCH] test(25-02): add failing tests for POST single and bulk upsert routes --- tests/routes/global-items.test.ts | 132 +++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/tests/routes/global-items.test.ts b/tests/routes/global-items.test.ts index 9af449a..cb8940f 100644 --- a/tests/routes/global-items.test.ts +++ b/tests/routes/global-items.test.ts @@ -111,7 +111,137 @@ describe("Global Item Routes", () => { }); }); - describe("GET /api/global-items/:id", () => { + describe("POST /api/global-items", () => { + it("returns 200 with item and created=true on new item", async () => { + const res = await app.request("/api/global-items", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ brand: "Revelate Designs", model: "Terrapin System" }), + }); + expect(res.status).toBe(200); + + const body = await res.json(); + expect(body.item.brand).toBe("Revelate Designs"); + expect(body.item.model).toBe("Terrapin System"); + expect(body.created).toBe(true); + }); + + it("returns 200 with created=false when upserting existing item", async () => { + await insertGlobalItem(db, "Revelate Designs", "Terrapin System"); + + const res = await app.request("/api/global-items", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + brand: "Revelate Designs", + model: "Terrapin System", + description: "Updated description", + }), + }); + expect(res.status).toBe(200); + + const body = await res.json(); + expect(body.created).toBe(false); + expect(body.item.description).toBe("Updated description"); + }); + + it("returns 400 when brand is missing", async () => { + const res = await app.request("/api/global-items", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model: "Terrapin System" }), + }); + expect(res.status).toBe(400); + }); + + it("returns 400 when model is missing", async () => { + const res = await app.request("/api/global-items", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ brand: "Revelate Designs" }), + }); + expect(res.status).toBe(400); + }); +}); + +describe("POST /api/global-items/bulk", () => { + it("returns 200 with created/updated counts", async () => { + const res = await app.request("/api/global-items/bulk", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + items: [ + { brand: "Revelate Designs", model: "Terrapin System" }, + { brand: "Apidura", model: "Handlebar Pack" }, + ], + }), + }); + expect(res.status).toBe(200); + + const body = await res.json(); + expect(body.created).toBe(2); + expect(body.updated).toBe(0); + expect(body.items).toHaveLength(2); + }); + + it("returns correct counts for mix of new and existing items", async () => { + await insertGlobalItem(db, "Revelate Designs", "Terrapin System"); + + const res = await app.request("/api/global-items/bulk", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + items: [ + { brand: "Revelate Designs", model: "Terrapin System" }, + { brand: "Apidura", model: "Handlebar Pack" }, + ], + }), + }); + expect(res.status).toBe(200); + + const body = await res.json(); + expect(body.created).toBe(1); + expect(body.updated).toBe(1); + }); + + it("returns 400 when items array is empty", async () => { + const res = await app.request("/api/global-items/bulk", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ items: [] }), + }); + expect(res.status).toBe(400); + }); + + it("returns 400 when items array exceeds 100", async () => { + const items = Array.from({ length: 101 }, (_, i) => ({ + brand: `Brand${i}`, + model: `Model${i}`, + })); + const res = await app.request("/api/global-items/bulk", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ items }), + }); + expect(res.status).toBe(400); + }); + + it("returns 400 for invalid item in array (missing brand)", async () => { + const res = await app.request("/api/global-items/bulk", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + items: [ + { brand: "Revelate Designs", model: "Terrapin System" }, + { model: "Invalid Item without brand" }, + ], + }), + }); + expect(res.status).toBe(400); + }); +}); + +describe("GET /api/global-items/:id", () => { it("returns item with ownerCount", async () => { const gi = await insertGlobalItem(db, "MSR", "PocketRocket 2");