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"] || "member", }; next(); }, locationAccess: (req, res, next) => { req.storeLocation = { id: Number.parseInt(req.params.locationId, 10) }; 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(), deleteAvailableItem: jest.fn(), getAvailableItems: jest.fn(), importCurrentItems: jest.fn(), updateAvailableItem: jest.fn(), })); jest.mock("../controllers/stores.controller", () => ({ addLocationToStore: jest.fn((req, res) => res.status(201).json({ message: "location" })), createHouseholdStore: jest.fn((req, res) => res.status(201).json({ message: "store" })), createZone: jest.fn((req, res) => res.status(201).json({ message: "zone" })), deleteHouseholdStore: jest.fn((req, res) => res.json({ message: "deleted store" })), deleteLocation: jest.fn((req, res) => res.json({ message: "deleted location" })), deleteZone: jest.fn((req, res) => res.json({ message: "deleted zone" })), getHouseholdStores: jest.fn((req, res) => res.json([{ id: 2, name: "Costco" }])), getLocationZones: jest.fn((req, res) => res.json({ zones: [] })), setDefaultLocation: jest.fn((req, res) => res.json({ message: "default" })), updateHouseholdStore: jest.fn((req, res) => res.json({ message: "updated store" })), updateLocation: jest.fn((req, res) => res.json({ message: "updated location" })), updateZone: jest.fn((req, res) => res.json({ message: "updated zone" })), })); const express = require("express"); const request = require("supertest"); const router = require("../routes/households.routes"); const storesController = require("../controllers/stores.controller"); describe("store location routes", () => { let app; beforeEach(() => { app = express(); app.use(express.json()); app.use("/households", router); jest.clearAllMocks(); }); test("members can list household store locations", async () => { const response = await request(app).get("/households/1/stores"); expect(response.status).toBe(200); expect(storesController.getHouseholdStores).toHaveBeenCalled(); }); test("members cannot create household stores", async () => { const response = await request(app) .post("/households/1/stores") .set("x-household-role", "member") .send({ name: "Costco" }); expect(response.status).toBe(403); expect(storesController.createHouseholdStore).not.toHaveBeenCalled(); }); test("admins can create household stores", async () => { const response = await request(app) .post("/households/1/stores") .set("x-household-role", "admin") .send({ name: "Costco", location_name: "Fontana" }); expect(response.status).toBe(201); expect(storesController.createHouseholdStore).toHaveBeenCalled(); }); test("members can list zones but cannot create zones", async () => { const listResponse = await request(app) .get("/households/1/locations/2/zones") .set("x-household-role", "member"); const createResponse = await request(app) .post("/households/1/locations/2/zones") .set("x-household-role", "member") .send({ name: "Produce", sort_order: 10 }); expect(listResponse.status).toBe(200); expect(createResponse.status).toBe(403); expect(storesController.getLocationZones).toHaveBeenCalled(); expect(storesController.createZone).not.toHaveBeenCalled(); }); test("admins can update zone order", async () => { const response = await request(app) .patch("/households/1/locations/2/zones/9") .set("x-household-role", "admin") .send({ sort_order: 20 }); expect(response.status).toBe(200); expect(storesController.updateZone).toHaveBeenCalled(); }); });