import { beforeEach, describe, expect, it } from "vitest" import { formatSelectionContext } from "@/lib/chat-helpers" import { EMPTY_SUMMARY } from "@/lib/diagram-diff" import { withPageDefaults } from "@/lib/drawio/drawio-config" import { describeChanges } from "@/lib/version-text" import { MAX_VERSIONS, useVersionsStore, versionsFromLegacyHistory, } from "@/stores/versions-store" describe("withPageDefaults", () => { it("adds page and grid when the model has none", () => { expect(withPageDefaults("")).toBe( '', ) }) it("keeps values the diagram already sets", () => { const xml = '' expect(withPageDefaults(xml)).toBe(xml) }) it("reads attributes written with spaces around =", () => { const xml = '' expect(withPageDefaults(xml)).toBe(xml) }) it("handles self-closing models and several pages", () => { const xml = '' expect(withPageDefaults(xml)).toBe( '', ) }) }) describe("describeChanges", () => { const en = { shapesAddedOne: "added 1 shape", shapesAddedOther: "added {count} shapes", edgesChangedOne: "changed 1 connector", edgesChangedOther: "changed {count} connectors", noChanges: "No visible changes", listSeparator: ", ", } it("uses singular and plural forms and sentence case", () => { expect( describeChanges( { ...EMPTY_SUMMARY, shapesAdded: 2, edgesChanged: 1 }, en, ), ).toBe("Added 2 shapes, changed 1 connector") }) it("says so when nothing changed", () => { expect(describeChanges({ ...EMPTY_SUMMARY }, en)).toBe( "No visible changes", ) }) it("uses the language's list separator", () => { const zh = { shapesAddedOther: "新增 {count} 个图形", edgesChangedOne: "改了 1 条连线", listSeparator: ",", } expect( describeChanges( { ...EMPTY_SUMMARY, shapesAdded: 3, edgesChanged: 1 }, zh, ), ).toBe("新增 3 个图形,改了 1 条连线") }) }) describe("formatSelectionContext", () => { it("lists selected ids with their labels", () => { const text = formatSelectionContext([ { id: "4", label: "EC2" }, { id: "cf", label: "" }, ]) expect(text).toContain('- id="4" (EC2)') expect(text).toContain('- id="cf"') expect(text).not.toContain('id="cf" (') }) it("returns nothing for missing or malformed input", () => { expect(formatSelectionContext(undefined)).toBe("") expect(formatSelectionContext("4")).toBe("") expect(formatSelectionContext([{ label: "no id" }])).toBe("") }) it("strips quotes and newlines and limits length and count", () => { const many = Array.from({ length: 80 }, (_, i) => ({ id: `c${i}`, label: `line\n"quoted"${"x".repeat(200)}`, })) const text = formatSelectionContext(many) const lines = text.split("\n").filter((l) => l.startsWith("- id=")) expect(lines).toHaveLength(50) // The model is told the list is cut short expect(text).toContain("- and 30 more selected shapes not listed") expect(text).not.toContain('"quoted"') expect(lines[0].length).toBeLessThan(130) }) }) describe("versions store", () => { beforeEach(() => useVersionsStore.getState().clear()) const add = (n: number) => useVersionsStore.getState().addVersion({ xml: ``, beforeXml: ``, turnIndex: n, summary: { ...EMPTY_SUMMARY }, }) it("keeps the before-XML only on the newest version", () => { add(0) add(2) const [first, second] = useVersionsStore.getState().versions expect(first.beforeXml).toBeUndefined() expect(second.beforeXml).toBe('') }) it("keeps at most MAX_VERSIONS versions", () => { for (let i = 0; i < MAX_VERSIONS + 5; i++) add(i) const { versions } = useVersionsStore.getState() expect(versions).toHaveLength(MAX_VERSIONS) expect(versions[0].turnIndex).toBe(5) }) it("drops versions from a turn that is re-run, none left on the canvas", () => { add(0) add(2) add(4) useVersionsStore.getState().removeFromTurn(2) const state = useVersionsStore.getState() expect(state.versions.map((v) => v.turnIndex)).toEqual([0]) expect(state.onCanvasVersionId).toBeNull() }) it("hand edits clear both version flags", () => { const id = add(0) expect(useVersionsStore.getState().onCanvasVersionId).toBe(id) useVersionsStore.getState().clearCanvasFlags() let state = useVersionsStore.getState() expect(state.onCanvasVersionId).toBeNull() expect(state.versions[0].onCanvas).toBeUndefined() useVersionsStore.getState().setUndone(id) useVersionsStore.getState().clearCanvasFlags() state = useVersionsStore.getState() expect(state.undoneVersionId).toBeNull() expect(state.versions[0].undone).toBeUndefined() }) it("converts the old history list", () => { const versions = versionsFromLegacyHistory([ { svg: "data:image/svg+xml;base64,AA", xml: "" }, ]) expect(versions).toHaveLength(1) expect(versions[0]).toMatchObject({ xml: "", turnIndex: -1 }) expect(versionsFromLegacyHistory(undefined)).toEqual([]) }) })