203 lines
6.0 KiB
JavaScript
203 lines
6.0 KiB
JavaScript
jest.mock("../models/available-item.model", () => ({
|
|
createAvailableItem: jest.fn(),
|
|
deleteAvailableItem: jest.fn(),
|
|
getAvailableItemById: jest.fn(),
|
|
importCurrentListItems: jest.fn(),
|
|
listAvailableItems: jest.fn(),
|
|
updateAvailableItem: jest.fn(),
|
|
}));
|
|
|
|
jest.mock("../models/list.model.v2", () => ({
|
|
deleteClassification: jest.fn(),
|
|
upsertClassification: jest.fn(),
|
|
}));
|
|
|
|
jest.mock("../utils/logger", () => ({
|
|
logError: jest.fn(),
|
|
}));
|
|
|
|
const AvailableItems = require("../models/available-item.model");
|
|
const List = require("../models/list.model.v2");
|
|
const controller = require("../controllers/available-items.controller");
|
|
|
|
function createResponse() {
|
|
const res = {};
|
|
res.status = jest.fn().mockReturnValue(res);
|
|
res.json = jest.fn().mockReturnValue(res);
|
|
return res;
|
|
}
|
|
|
|
describe("available-items.controller", () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
AvailableItems.createAvailableItem.mockResolvedValue({ item_id: 99, item_name: "milk" });
|
|
AvailableItems.getAvailableItemById.mockResolvedValue({
|
|
item_id: 99,
|
|
item_name: "milk",
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
});
|
|
AvailableItems.updateAvailableItem.mockResolvedValue({ item_id: 99, item_name: "milk" });
|
|
AvailableItems.deleteAvailableItem.mockResolvedValue(true);
|
|
AvailableItems.importCurrentListItems.mockResolvedValue(2);
|
|
AvailableItems.listAvailableItems.mockResolvedValue([]);
|
|
List.upsertClassification.mockResolvedValue(undefined);
|
|
List.deleteClassification.mockResolvedValue(false);
|
|
});
|
|
|
|
test("creates an available item and persists classification metadata", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2" },
|
|
body: {
|
|
item_name: "milk",
|
|
classification: JSON.stringify({
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
}),
|
|
},
|
|
processedImage: null,
|
|
};
|
|
const res = createResponse();
|
|
|
|
await controller.createAvailableItem(req, res);
|
|
|
|
expect(AvailableItems.createAvailableItem).toHaveBeenCalledWith("1", "2", "milk", null, null);
|
|
expect(List.upsertClassification).toHaveBeenCalledWith(
|
|
"1",
|
|
"2",
|
|
99,
|
|
expect.objectContaining({
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
})
|
|
);
|
|
expect(res.status).toHaveBeenCalledWith(201);
|
|
});
|
|
|
|
test("rejects invalid item_group values", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2" },
|
|
body: {
|
|
item_name: "milk",
|
|
classification: JSON.stringify({
|
|
item_type: "dairy",
|
|
item_group: "Bread",
|
|
}),
|
|
},
|
|
};
|
|
const res = createResponse();
|
|
|
|
await controller.createAvailableItem(req, res);
|
|
|
|
expect(AvailableItems.createAvailableItem).not.toHaveBeenCalled();
|
|
expect(res.status).toHaveBeenCalledWith(400);
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
error: expect.objectContaining({
|
|
message: "Invalid item_group for selected item_type",
|
|
}),
|
|
})
|
|
);
|
|
});
|
|
|
|
test("clears classification on update when classification is explicitly empty", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2", itemId: "99" },
|
|
body: {
|
|
classification: "null",
|
|
},
|
|
processedImage: null,
|
|
};
|
|
const res = createResponse();
|
|
|
|
await controller.updateAvailableItem(req, res);
|
|
|
|
expect(List.deleteClassification).toHaveBeenCalledWith("1", "2", 99);
|
|
expect(res.status).not.toHaveBeenCalledWith(400);
|
|
});
|
|
|
|
test("imports current list items and reports the import count", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2" },
|
|
};
|
|
const res = createResponse();
|
|
|
|
await controller.importCurrentItems(req, res);
|
|
|
|
expect(AvailableItems.importCurrentListItems).toHaveBeenCalledWith("1", "2");
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
imported_count: 2,
|
|
})
|
|
);
|
|
});
|
|
|
|
test("clears managed settings without removing the underlying item", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2", itemId: "99" },
|
|
};
|
|
const res = createResponse();
|
|
|
|
AvailableItems.deleteAvailableItem.mockResolvedValueOnce(false);
|
|
List.deleteClassification.mockResolvedValueOnce(true);
|
|
|
|
await controller.deleteAvailableItem(req, res);
|
|
|
|
expect(AvailableItems.deleteAvailableItem).toHaveBeenCalledWith("1", "2", 99);
|
|
expect(List.deleteClassification).toHaveBeenCalledWith("1", "2", 99);
|
|
expect(res.json).toHaveBeenCalledWith({ message: "Store item settings cleared" });
|
|
});
|
|
|
|
test("returns an empty catalog payload when the available items table is missing", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2" },
|
|
query: {},
|
|
};
|
|
const res = createResponse();
|
|
|
|
AvailableItems.listAvailableItems.mockRejectedValueOnce({
|
|
code: "42P01",
|
|
message: 'relation "household_store_available_items" does not exist',
|
|
});
|
|
|
|
await controller.getAvailableItems(req, res);
|
|
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
items: [],
|
|
catalog_ready: false,
|
|
})
|
|
);
|
|
});
|
|
|
|
test("returns a setup error when creating while the available items table is missing", async () => {
|
|
const req = {
|
|
params: { householdId: "1", storeId: "2" },
|
|
body: {
|
|
item_name: "milk",
|
|
},
|
|
processedImage: null,
|
|
};
|
|
const res = createResponse();
|
|
|
|
AvailableItems.createAvailableItem.mockRejectedValueOnce({
|
|
code: "42P01",
|
|
message: 'relation "household_store_available_items" does not exist',
|
|
});
|
|
|
|
await controller.createAvailableItem(req, res);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(503);
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
error: expect.objectContaining({
|
|
message: expect.stringContaining("latest database migration"),
|
|
}),
|
|
})
|
|
);
|
|
});
|
|
});
|