177 lines
4.7 KiB
JavaScript
177 lines
4.7 KiB
JavaScript
jest.mock("../db/pool", () => ({
|
|
query: jest.fn(),
|
|
}));
|
|
|
|
const pool = require("../db/pool");
|
|
const List = require("../models/list.model.v2");
|
|
|
|
describe("list.model.v2 addOrUpdateItem", () => {
|
|
beforeEach(() => {
|
|
pool.query.mockReset();
|
|
});
|
|
|
|
test("returns item metadata when creating a new household list item", async () => {
|
|
pool.query
|
|
.mockResolvedValueOnce({ rowCount: 0, rows: [] })
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [{ id: 55 }] })
|
|
.mockResolvedValueOnce({ rowCount: 0, rows: [] })
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [{ id: 88 }] });
|
|
|
|
const result = await List.addOrUpdateItem(1, 2, "Milk", 3, 7);
|
|
|
|
expect(result).toEqual({
|
|
listId: 88,
|
|
itemId: 55,
|
|
itemName: "milk",
|
|
isNew: true,
|
|
});
|
|
expect(pool.query).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT id FROM items WHERE name ILIKE $1",
|
|
["milk"]
|
|
);
|
|
expect(pool.query).toHaveBeenNthCalledWith(
|
|
2,
|
|
"INSERT INTO items (name) VALUES ($1) RETURNING id",
|
|
["milk"]
|
|
);
|
|
});
|
|
|
|
test("returns item metadata when updating an existing household list item", async () => {
|
|
pool.query
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [{ id: 55 }] })
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [{ id: 88, bought: false }] })
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [] });
|
|
|
|
const result = await List.addOrUpdateItem(1, 2, "Milk", 4, 7);
|
|
|
|
expect(result).toEqual({
|
|
listId: 88,
|
|
itemId: 55,
|
|
itemName: "milk",
|
|
isNew: false,
|
|
});
|
|
expect(pool.query).toHaveBeenNthCalledWith(
|
|
3,
|
|
expect.stringContaining("UPDATE household_lists"),
|
|
[4, 88]
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("list.model.v2 classification helpers", () => {
|
|
beforeEach(() => {
|
|
pool.query.mockReset();
|
|
});
|
|
|
|
test("gets classification using household, store, and item ids", async () => {
|
|
pool.query.mockResolvedValueOnce({
|
|
rowCount: 1,
|
|
rows: [
|
|
{
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
confidence: 1,
|
|
source: "user",
|
|
},
|
|
],
|
|
});
|
|
|
|
const result = await List.getClassification(1, 2, 55);
|
|
|
|
expect(result).toEqual({
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
confidence: 1,
|
|
source: "user",
|
|
});
|
|
expect(pool.query).toHaveBeenCalledWith(
|
|
expect.stringContaining("WHERE household_id = $1 AND store_id = $2 AND item_id = $3"),
|
|
[1, 2, 55]
|
|
);
|
|
});
|
|
|
|
test("upserts classification using store-scoped conflict target", async () => {
|
|
pool.query.mockResolvedValueOnce({
|
|
rowCount: 1,
|
|
rows: [
|
|
{
|
|
household_id: 1,
|
|
store_id: 2,
|
|
item_id: 55,
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
confidence: 1,
|
|
source: "user",
|
|
},
|
|
],
|
|
});
|
|
|
|
const result = await List.upsertClassification(1, 2, 55, {
|
|
item_type: "dairy",
|
|
item_group: "Milk",
|
|
zone: "Dairy & Refrigerated",
|
|
confidence: 1,
|
|
source: "user",
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
household_id: 1,
|
|
store_id: 2,
|
|
item_id: 55,
|
|
item_type: "dairy",
|
|
})
|
|
);
|
|
expect(pool.query).toHaveBeenCalledWith(
|
|
expect.stringContaining("ON CONFLICT (household_id, store_id, item_id)"),
|
|
[1, 2, 55, "dairy", "Milk", "Dairy & Refrigerated", 1, "user"]
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("list.model.v2 suggestions", () => {
|
|
beforeEach(() => {
|
|
pool.query.mockReset();
|
|
});
|
|
|
|
test("returns catalog suggestions when a household-store catalog exists", async () => {
|
|
pool.query
|
|
.mockResolvedValueOnce({ rowCount: 1, rows: [{ "?column?": 1 }] })
|
|
.mockResolvedValueOnce({
|
|
rowCount: 1,
|
|
rows: [{ item_name: "milk", sort_order: 0 }],
|
|
});
|
|
|
|
const result = await List.getSuggestions("mi", 1, 2);
|
|
|
|
expect(result).toEqual([{ item_name: "milk", sort_order: 0 }]);
|
|
expect(pool.query).toHaveBeenNthCalledWith(
|
|
1,
|
|
expect.stringContaining("FROM household_store_available_items"),
|
|
[1, 2]
|
|
);
|
|
});
|
|
|
|
test("falls back to legacy suggestions when catalog is empty", async () => {
|
|
pool.query
|
|
.mockResolvedValueOnce({ rowCount: 0, rows: [] })
|
|
.mockResolvedValueOnce({
|
|
rowCount: 1,
|
|
rows: [{ item_name: "milk", sort_order: 1 }],
|
|
});
|
|
|
|
const result = await List.getSuggestions("mi", 1, 2);
|
|
|
|
expect(result).toEqual([{ item_name: "milk", sort_order: 1 }]);
|
|
expect(pool.query).toHaveBeenNthCalledWith(
|
|
2,
|
|
expect.stringContaining("LEFT JOIN household_lists"),
|
|
["%mi%", 1, 2]
|
|
);
|
|
});
|
|
});
|