test(stock): cover validation + not_found + per-row independence

This commit is contained in:
Dave 2026-08-31 16:48:40 +02:00
parent 86eba97d33
commit ab639eea6d

View file

@ -186,3 +186,95 @@ describe("updateStockItemsPricing — stock_ledger audit on cost change", () =>
]); ]);
}); });
}); });
describe("updateStockItemsPricing — input validation", () => {
it("rejects negative numbers", async () => {
const result = await updateStockItemsPricing({
pb: { collection: () => ({ getOne: vi.fn(), update: vi.fn(), create: vi.fn() }) } as never,
updates: [{ id: "abcdefghijklmno", costPrice: -1 }],
actor: { id: "useropid1234567", name: "Gary" },
});
expect(result.results[0]).toMatchObject({
ok: false,
reason: "validation_error",
});
});
it("rejects forbidden fields", async () => {
const result = await updateStockItemsPricing({
pb: { collection: () => ({ getOne: vi.fn(), update: vi.fn(), create: vi.fn() }) } as never,
updates: [
{ id: "abcdefghijklmno", costPrice: 1, maliciousFlag: true } as never,
],
actor: { id: "useropid1234567", name: "Gary" },
});
expect(result.results[0]).toMatchObject({
ok: false,
reason: "forbidden_field",
});
});
});
describe("updateStockItemsPricing — not_found and per-row independence", () => {
it("returns not_found when the row is gone", async () => {
const pb = {
collection: (name: string) => {
if (name === "stock_items") {
return {
getOne: vi.fn().mockRejectedValue(new Error("404 not found")),
update: vi.fn(),
create: vi.fn(),
};
}
if (name === "stock_ledger") {
return { create: vi.fn() };
}
throw new Error(`unexpected ${name}`);
},
};
const result = await updateStockItemsPricing({
pb: pb as never,
updates: [{ id: "missing00000000x", costPrice: 1 }],
actor: { id: "useropid1234567", name: "Gary" },
});
expect(result.results[0]).toMatchObject({
ok: false,
reason: "not_found",
});
});
it("does not abort sibling rows when one is not_found", async () => {
const updated = { id: "abcdefghijklmno", cost_price: 5, selling_price: 0, markup: 0 };
let nextIsMissing = true;
const pb = {
collection: (name: string) => {
if (name === "stock_items") {
return {
getOne: vi.fn().mockImplementation(async () => {
if (nextIsMissing) {
nextIsMissing = false;
throw new Error("404 not found");
}
return updated;
}),
update: vi.fn().mockResolvedValue(updated),
create: vi.fn(),
};
}
if (name === "stock_ledger") return { create: vi.fn().mockResolvedValue({ id: "l1" }) };
throw new Error(`unexpected ${name}`);
},
};
const result = await updateStockItemsPricing({
pb: pb as never,
updates: [
{ id: "missing00000000x", costPrice: 1 },
{ id: "abcdefghijklmno", costPrice: 5 },
],
actor: { id: "useropid1234567", name: "Gary" },
});
expect(result.summary).toEqual({ total: 2, succeeded: 1, failed: 1 });
expect(result.results[0]).toMatchObject({ ok: false, reason: "not_found" });
expect(result.results[1]).toMatchObject({ ok: true });
});
});