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 => ({ 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); }); });