jest.mock("../models/list.model.v2", () => ({ addHistoryRecord: jest.fn(), addOrUpdateItem: jest.fn(), })); jest.mock("../models/household.model", () => ({ isHouseholdMember: jest.fn(), })); jest.mock("../utils/logger", () => ({ logError: jest.fn(), })); const List = require("../models/list.model.v2"); const householdModel = require("../models/household.model"); const controller = require("../controllers/lists.controller.v2"); function createResponse() { const res = {}; res.status = jest.fn().mockReturnValue(res); res.json = jest.fn().mockReturnValue(res); return res; } describe("lists.controller.v2 addItem", () => { beforeEach(() => { List.addOrUpdateItem.mockResolvedValue({ listId: 42, itemName: "milk", isNew: true, }); List.addHistoryRecord.mockResolvedValue(undefined); householdModel.isHouseholdMember.mockResolvedValue(true); }); test("records history for selected added_for_user_id when member is valid", async () => { const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1", added_for_user_id: "9" }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(householdModel.isHouseholdMember).toHaveBeenCalledWith("1", 9); expect(List.addOrUpdateItem).toHaveBeenCalled(); expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 9); expect(res.status).not.toHaveBeenCalledWith(400); }); test("records history using request user when added_for_user_id is not provided", async () => { const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1" }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(householdModel.isHouseholdMember).not.toHaveBeenCalled(); expect(List.addOrUpdateItem).toHaveBeenCalled(); expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 7); expect(res.status).not.toHaveBeenCalledWith(400); }); test("records history using request user when added_for_user_id is blank", async () => { const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1", added_for_user_id: " " }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(householdModel.isHouseholdMember).not.toHaveBeenCalled(); expect(List.addOrUpdateItem).toHaveBeenCalled(); expect(List.addHistoryRecord).toHaveBeenCalledWith(42, "1", 7); expect(res.status).not.toHaveBeenCalledWith(400); }); test("rejects invalid added_for_user_id", async () => { const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1", added_for_user_id: "abc" }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(List.addOrUpdateItem).not.toHaveBeenCalled(); expect(List.addHistoryRecord).not.toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ error: expect.objectContaining({ message: "Added-for user ID must be a positive integer", }), }) ); }); test("rejects malformed numeric-looking added_for_user_id", async () => { const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1", added_for_user_id: "9abc" }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(List.addOrUpdateItem).not.toHaveBeenCalled(); expect(List.addHistoryRecord).not.toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ error: expect.objectContaining({ message: "Added-for user ID must be a positive integer", }), }) ); }); test("rejects added_for_user_id when target user is not household member", async () => { householdModel.isHouseholdMember.mockResolvedValue(false); const req = { params: { householdId: "1", storeId: "2" }, body: { item_name: "milk", quantity: "1", added_for_user_id: "11" }, user: { id: 7 }, processedImage: null, }; const res = createResponse(); await controller.addItem(req, res); expect(householdModel.isHouseholdMember).toHaveBeenCalledWith("1", 11); expect(List.addOrUpdateItem).not.toHaveBeenCalled(); expect(List.addHistoryRecord).not.toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ error: expect.objectContaining({ message: "Selected user is not a member of this household", }), }) ); }); });