import { describe, expect, it } from "vitest" import { extractCompleteMxCells, isMxCellXmlComplete } from "@/lib/utils" import { expandCompactCells, foldCells, } from "@/packages/mcp-server/src/compact-cells.ts" import { editDiagram } from "@/packages/mcp-server/src/edit-diagram.ts" import { prepareNewDiagram } from "@/packages/mcp-server/src/new-diagram.ts" import { normalizeToMxfile, wrapCellsInModel, } from "@/packages/mcp-server/src/pages.ts" const shape = '' const shapeLong = '' const edge = '' const edgeLong = '' /** Cells compared by what they mean, not by attribute order */ function canonical(xml: string): string { const doc = new DOMParser().parseFromString( `${xml}`, "text/xml", ) const describe = (el: Element): string => { const attrs = Array.from(el.attributes) .map((a) => `${a.name}=${a.value}`) .sort() .join(" ") const children = Array.from(el.children).map(describe).join("") return `<${el.tagName} ${attrs}>${children}` } return Array.from(doc.documentElement.children).map(describe).join("\n") } describe("expandCompactCells", () => { it("gives a compact shape its flags, parent and geometry", () => { expect(expandCompactCells(shape)).toBe(shapeLong) }) it("gives a compact edge its flags, parent and relative geometry", () => { expect(expandCompactCells(edge)).toBe(edgeLong) }) it("keeps an explicit parent and accepts width/height as names", () => { const inLane = '' expect(expandCompactCells(inLane)).toBe( '', ) }) it("fills in a default position and size when some are missing", () => { expect(expandCompactCells('')).toBe( '', ) }) it("lets an explicit geometry win over compact attributes", () => { // The stray attributes stay as written; the geometry is the one used const both = '' expect(expandCompactCells(both)).toBe( '', ) }) it("adds the relative geometry to a long-form edge that has none", () => { const noGeometry = '' expect(expandCompactCells(noGeometry)).toBe(edgeLong) }) it("leaves root cells, long-form cells and edge labels alone", () => { const roots = '' const label = '' expect(expandCompactCells(roots + shapeLong + edgeLong + label)).toBe( roots + shapeLong + edgeLong + label, ) }) it("works on a cell inside a UserObject wrapper", () => { const wrapped = '' expect(expandCompactCells(wrapped)).toBe( '', ) }) }) describe("foldCells", () => { it("writes plain shapes and edges compactly", () => { expect(foldCells(shapeLong)).toBe(shape) expect(foldCells(edgeLong)).toBe(edge) }) it("keeps a parent other than 1 and leaves special cells as written", () => { const inLane = '' expect(foldCells(inLane)).toBe( '', ) const waypoints = '' const label = '' const sourcePoint = '' const roots = '' const wrongAs = '' for (const xml of [waypoints, label, sourcePoint, roots, wrongAs]) { expect(foldCells(xml)).toBe(xml) } }) it("round-trips through expandCompactCells", () => { const page = `${shapeLong}${edgeLong}` const folded = foldCells(page) expect(folded).not.toContain("vertex=") expect(canonical(expandCompactCells(folded))).toBe(canonical(page)) }) }) describe("compact cells through the pipeline", () => { const geometryOf = (xml: string, id: string) => xml.match( new RegExp(`]*>(]*/>)`), )?.[1] it("prepareNewDiagram expands them and still adds the defaults", () => { const prepared = prepareNewDiagram(`${shape}\n${edge}`) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain( 'style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"', ) expect(geometryOf(prepared.xml, "2")).toBe( '', ) expect(prepared.xml).toContain( '', ) }) it("editDiagram accepts a compact cell in new_xml", () => { const file = normalizeToMxfile(wrapCellsInModel(shapeLong), { pageId: "p1", pageName: "Page-1", }) ?? "" const outcome = editDiagram( file, [ { operation: "add", cell_id: "3", new_xml: '', }, { operation: "update", cell_id: "2", new_xml: '', }, ], {}, ) expect(outcome.ok).toBe(true) if (!outcome.ok) return expect(outcome.xml).toContain('value="Next"') expect(outcome.xml).toContain('value="Begin"') expect(geometryOf(outcome.xml, "3")).toBe( '', ) }) }) describe("a compact cell with a slip", () => { it("repairs a missing closing quote before the slash", () => { const prepared = prepareNewDiagram( '', ) }) }) describe("review round: cells the model may write", () => { it("escapes a double quote from a single-quoted value", () => { const out = expandCompactCells( ``, ) expect(out).toContain('value="Say "hi""') const prepared = prepareNewDiagram( ``, ) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain('value="a" visible="0"') expect(prepared.xml).not.toContain(' visible="0"') const folded = foldCells( ``, ) expect(folded).toBe( '', ) }) it("accepts labels with > in compact self-closing cells", () => { const prepared = prepareNewDiagram( ` `, ) expect(prepared.ok).toBe(true) expect( isMxCellXmlComplete( '', ), ).toBe(true) expect( extractCompleteMxCells( '\n') }) it("infers a vertex for an edge label with a geometry and an edge for a connection with a size", () => { const label = '' expect(expandCompactCells(label)).toBe( '', ) expect( expandCompactCells( '', ), ).toBe( '', ) // A dangling edge has only one end expect( expandCompactCells(''), ).toBe( '', ) }) it("does not take a geometry inside custom data for the cell's own", () => { const out = expandCompactCells( '', ) expect(out).toBe( '', ) }) it("keeps stray size attributes when the cell has its own geometry", () => { const xml = '' expect(expandCompactCells(xml)).toBe(xml) expect(foldCells(xml)).toBe(xml) }) it("ignores prototype names and folds only cells that name their parent", () => { expect(expandCompactCells('')).toBe( '', ) const noParent = '' expect(foldCells(noParent)).toBe(noParent) }) it("puts a compact cell on the page's first layer when editing", () => { const file = `${shapeLong.replace('parent="1"', 'parent="L1"')}` const outcome = editDiagram( file, [ { operation: "add", cell_id: "3", new_xml: '', }, ], {}, ) expect(outcome.ok).toBe(true) if (!outcome.ok) return expect(outcome.xml).toContain( '', ) }) it("refuses a compact shape with a root cell id instead of dropping it", () => { const prepared = prepareNewDiagram( '', ) expect(prepared.ok).toBe(false) if (!prepared.ok) expect(prepared.error).toContain("root cells") }) it("repairs the quote slip only on a cell's last numeric attribute", () => { expect( isMxCellXmlComplete('', ) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain('value="5/>"') expect(prepared.xml).toContain( '', ) }) it("closes a compact cell written without the slash", () => { const prepared = prepareNewDiagram( '\n', ) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain('value="A"') expect(prepared.xml).toContain('value="B"') expect(prepared.fixes.join()).toContain("without the slash") }) }) describe("a long-form cell missing its closing tag next to compact cells", () => { it("is closed before the compact cell that follows", () => { const prepared = prepareNewDiagram( ` `, ) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain('') expect(prepared.xml).toContain('value="C"') expect((prepared.xml.match(/ { const prepared = prepareNewDiagram( ` `, ) expect(prepared.ok).toBe(true) if (!prepared.ok) return expect(prepared.xml).toContain('value="A"') expect(prepared.xml).toContain('value="B"') expect((prepared.xml.match(/