148 lines
5.2 KiB
JavaScript
148 lines
5.2 KiB
JavaScript
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();
|
|
},
|
|
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((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" })),
|
|
}));
|
|
|
|
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([])),
|
|
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 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();
|
|
});
|
|
|
|
test("members can create available items on location-scoped routes", async () => {
|
|
const response = await request(app)
|
|
.post("/households/1/locations/2/available-items")
|
|
.set("x-household-role", "member")
|
|
.send({ item_name: "milk" });
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(availableItemsController.createAvailableItem).toHaveBeenCalled();
|
|
});
|
|
|
|
test("members cannot delete available items on location-scoped routes", async () => {
|
|
const response = await request(app)
|
|
.delete("/households/1/locations/2/available-items/3")
|
|
.set("x-household-role", "member");
|
|
|
|
expect(response.status).toBe(403);
|
|
expect(availableItemsController.deleteAvailableItem).not.toHaveBeenCalled();
|
|
});
|
|
});
|