/** * Tests for wrapCellsInModel: the model may send only the mxCell elements of * a page, like in the web app, and the server adds the wrapper and root cells. */ import { beforeAll, describe, expect, it } from "vitest" import { installDomPolyfill } from "../src/dom.ts" beforeAll(() => { installDomPolyfill() }) import { prepareNewDiagram, reservedIdError } from "../src/new-diagram.ts" import { hasCells, wrapCellsInModel } from "../src/pages.ts" import { validateAndFixXml } from "../src/xml-validation.ts" const A = `` const B = `` const ROOTS = `` describe("wrapCellsInModel", () => { it("wraps sibling cells so they pass validation", () => { expect(validateAndFixXml(A + B).valid).toBe(false) const wrapped = wrapCellsInModel(A + B) expect(wrapped).toBe( `${ROOTS}${A}${B}`, ) expect(validateAndFixXml(wrapped).valid).toBe(true) }) it("replaces root cells the model wrote itself", () => { const wrapped = wrapCellsInModel( `${A}`, ) expect(wrapped.match(/id="0"/g)).toHaveLength(1) expect(wrapped.match(/id="1"/g)).toHaveLength(1) expect(wrapped).toContain(A) }) it("unwraps a and drops trailing provider tags", () => { const wrapped = wrapCellsInModel( `${A}`, ) expect(wrapped).toBe( `${ROOTS}${A}`, ) }) it("drops comments and text before the first cell", () => { const expected = `${ROOTS}${A}` expect(wrapCellsInModel(`Here is the diagram: ${A}`)).toBe(expected) expect(wrapCellsInModel(`\n${A}`)).toBe(expected) }) it("leaves and input unchanged", () => { const model = `${ROOTS}${A}` const file = `${model}` expect(wrapCellsInModel(model)).toBe(model) expect(wrapCellsInModel(file)).toBe(file) }) it("replaces root cells written over two lines", () => { const wrapped = wrapCellsInModel( `\n\n\n\n${A}`, ) expect(wrapped).toBe( `${ROOTS}${A}`, ) }) it("keeps a UserObject cell at the end", () => { const wrapped = `` expect(wrapCellsInModel(A + wrapped)).toContain(wrapped) expect(wrapCellsInModel(`${wrapped}`)).toBe( `${ROOTS}${wrapped}`, ) }) }) describe("hasCells", () => { it("counts cells written with single quotes", () => { expect(hasCells(``)).toBe(true) expect(hasCells(``)).toBe( false, ) }) it("counts a compressed page as having cells", () => { // draw.io's compressed format: the page's model is text expect( hasCells( `dZHBDoIwDIafhjtsGPWM6MkTB8/LVmBxrGQMQZ/eLRuIUS/bv/VfmybF`, ), ).toBe(true) }) it("counts cells with spaces around the =", () => { expect(hasCells(``)).toBe(true) expect( hasCells(``), ).toBe(false) }) }) describe("reservedIdError", () => { it("finds a shape that uses a root cell id", () => { expect(reservedIdError(A)).toBeNull() expect(reservedIdError(ROOTS + A)).toBeNull() expect( reservedIdError(``), ).toMatch(/"0" and "1"/) // A linked or labelled shape has its id on the wrapper expect( reservedIdError( ``, ), ).toMatch(/"0" and "1"/) // Other attributes ending in id, and id text inside a label expect( reservedIdError( ``, ), ).toBeNull() expect( reservedIdError( ``, ), ).toBeNull() expect( reservedIdError( ``, ), ).toBeNull() expect( reservedIdError( ``, ), ).toBeNull() // A whole model has its own root cells expect( reservedIdError( `${ROOTS}`, ), ).toBeNull() }) }) describe("prepareNewDiagram", () => { it("rejects a shape that uses a root cell id", () => { // It would clash with the added root cell "1" and be renamed, // which breaks the edges that point to it const cells = `` + `` const out = prepareNewDiagram(cells) expect(out.ok).toBe(false) if (out.ok) return expect(out.error).toMatch(/"0" and "1"/) }) it("still accepts the root cells sent along with the shapes", () => { const out = prepareNewDiagram( `${A}`, ) expect(out.ok).toBe(true) }) })