WFDASH-WEBAPP/src/lib/quote-assistant-merge.test.ts

67 lines
2.4 KiB
TypeScript
Raw Normal View History

import { describe, expect, it } from "vitest";
import { mergeItemsAfterAiRun } from "./quote-assistant-merge";
type Row = { id: string; description: string; cost_price: number; ai_fill?: unknown };
const row = (id: string, over: Partial<Row> = {}): Row => ({
id,
description: `item ${id}`,
cost_price: 0,
...over,
});
describe("mergeItemsAfterAiRun", () => {
it("takes the server row for lines the rep has not touched", () => {
const baseline = [row("a"), row("b")];
const local = [row("a"), row("b")];
const fresh = [row("a", { cost_price: 10, ai_fill: { status: "filled" } }), row("b")];
const out = mergeItemsAfterAiRun(local, baseline, fresh);
expect(out.items).toEqual(fresh);
expect(out.keptDirty).toEqual([]);
});
it("keeps a row with unsaved typing as the rep left it", () => {
const baseline = [row("a"), row("b")];
const local = [row("a", { description: "rep is typing" }), row("b")];
const fresh = [
row("a", { cost_price: 10, ai_fill: { status: "filled" } }),
row("b", { cost_price: 7, ai_fill: { status: "filled" } }),
];
const out = mergeItemsAfterAiRun(local, baseline, fresh);
expect(out.items[0]).toEqual(local[0]);
expect(out.items[1]).toEqual(fresh[1]);
expect(out.keptDirty).toEqual(["a"]);
});
it("follows the server's row set and order: new rows appear, deleted rows go", () => {
const baseline = [row("a"), row("b")];
const local = [row("a"), row("b")];
const fresh = [row("c"), row("a")];
const out = mergeItemsAfterAiRun(local, baseline, fresh);
expect(out.items.map((r) => r.id)).toEqual(["c", "a"]);
});
it("treats a local row with no baseline as dirty (added locally, never loaded)", () => {
const local = [row("a", { description: "x" })];
const fresh = [row("a")];
const out = mergeItemsAfterAiRun(local, [], fresh);
expect(out.items[0]).toEqual(local[0]);
expect(out.keptDirty).toEqual(["a"]);
});
it("compares values, not object identity or key order", () => {
const baseline = [{ id: "a", cost_price: 0, description: "d", ai_fill: { status: "no_match" } }];
const local = [{ description: "d", id: "a", ai_fill: { status: "no_match" }, cost_price: 0 }];
const fresh = [{ id: "a", cost_price: 5, description: "d", ai_fill: { status: "filled" } }];
const out = mergeItemsAfterAiRun(local, baseline, fresh);
expect(out.items).toEqual(fresh);
});
});