jest.mock("../middleware/auth", () => (req, res, next) => { req.user = { id: 42, role: "user" }; next(); }); jest.mock("../middleware/household", () => ({ householdAccess: (req, res, next) => { req.household = { id: Number.parseInt(req.params.householdId, 10), role: req.headers["x-household-role"] || "user", }; next(); }, requireHouseholdAdmin: (req, res, next) => { if (["owner", "admin"].includes(req.household?.role)) { return next(); } return res.status(403).json({ error: { code: "FORBIDDEN", message: "Admin role required" }, request_id: req.request_id, }); }, storeAccess: (req, res, next) => next(), })); jest.mock("../middleware/image", () => ({ upload: { single: () => (req, res, next) => next(), }, processImage: (req, res, next) => next(), })); jest.mock("../controllers/households.controller", () => ({ createHousehold: jest.fn(), deleteHousehold: jest.fn(), getHousehold: jest.fn(), getMembers: jest.fn(), getUserHouseholds: jest.fn(), joinHousehold: jest.fn(), refreshInviteCode: jest.fn(), removeMember: jest.fn(), updateHousehold: jest.fn(), updateMemberRole: jest.fn(), })); jest.mock("../controllers/lists.controller.v2", () => ({ addItem: jest.fn(), deleteItem: jest.fn(), getClassification: jest.fn(), getItemByName: jest.fn(), getList: jest.fn(), getRecentlyBought: jest.fn(), getSuggestions: jest.fn(), markBought: jest.fn(), setClassification: jest.fn(), updateItem: jest.fn(), updateItemImage: jest.fn(), })); jest.mock("../controllers/available-items.controller", () => ({ createAvailableItem: jest.fn((req, res) => res.status(201).json({ message: "created" })), deleteAvailableItem: jest.fn((req, res) => res.json({ message: "deleted" })), getAvailableItems: jest.fn((req, res) => res.json({ items: [] })), importCurrentItems: jest.fn((req, res) => res.json({ imported_count: 1 })), updateAvailableItem: jest.fn((req, res) => res.json({ message: "updated" })), })); const express = require("express"); const request = require("supertest"); const router = require("../routes/households.routes"); const availableItemsController = require("../controllers/available-items.controller"); describe("available-items routes", () => { let app; beforeEach(() => { app = express(); app.use(express.json()); app.use("/households", router); jest.clearAllMocks(); }); test("members can read available items", async () => { const response = await request(app).get("/households/1/stores/2/available-items"); expect(response.status).toBe(200); expect(availableItemsController.getAvailableItems).toHaveBeenCalled(); }); test("members cannot mutate available items", async () => { const response = await request(app) .post("/households/1/stores/2/available-items") .set("x-household-role", "user") .send({ item_name: "milk" }); expect(response.status).toBe(403); expect(availableItemsController.createAvailableItem).not.toHaveBeenCalled(); }); test("admins can create available items", async () => { const response = await request(app) .post("/households/1/stores/2/available-items") .set("x-household-role", "admin") .send({ item_name: "milk" }); expect(response.status).toBe(201); expect(availableItemsController.createAvailableItem).toHaveBeenCalled(); }); });