/**
* Unit tests for load_diagram's file parsing (load-diagram.ts).
*
* A .drawio file stores each page's either as plain XML or
* as draw.io's compressed default (encodeURIComponent → raw deflate →
* base64 text content). The loader must produce the canonical session
* shape: an whose every page is plain XML.
*/
import { deflateRawSync } from "node:zlib"
import { DOMParser } from "linkedom"
import { beforeAll, describe, expect, it } from "vitest"
import { installDomPolyfill } from "../src/dom.ts"
// Install the DOM polyfills exactly as index.ts does at runtime.
beforeAll(() => {
installDomPolyfill()
})
import {
decompressPageContent,
parseDrawioFileContent,
} from "../src/load-diagram.ts"
const MODEL_XML = ``
/** Compress a page body exactly the way draw.io does when saving. */
function drawioCompress(xml: string): string {
return deflateRawSync(
Buffer.from(encodeURIComponent(xml), "utf-8"),
).toString("base64")
}
const PLAIN_MXFILE = `${MODEL_XML}`
const COMPRESSED_MXFILE = `${drawioCompress(MODEL_XML)}`
describe("decompressPageContent", () => {
it("round-trips draw.io's compressed format", () => {
expect(decompressPageContent(drawioCompress(MODEL_XML))).toBe(MODEL_XML)
})
it("handles non-URI-encoded legacy payloads", () => {
const legacy = deflateRawSync(Buffer.from(MODEL_XML, "utf-8")).toString(
"base64",
)
expect(decompressPageContent(legacy)).toBe(MODEL_XML)
})
it("returns null for garbage", () => {
expect(decompressPageContent("not base64 deflate")).toBeNull()
})
})
describe("parseDrawioFileContent", () => {
it("passes a plain-XML mxfile through unchanged", () => {
const r = parseDrawioFileContent(PLAIN_MXFILE)
expect(r).toEqual({ ok: true, xml: PLAIN_MXFILE })
})
it("wraps a bare mxGraphModel into a one-page mxfile", () => {
const r = parseDrawioFileContent(MODEL_XML)
expect(r.ok).toBe(true)
if (r.ok) {
expect(r.xml).toContain(" {
const r = parseDrawioFileContent(
MODEL_XML.replace("", ""),
)
expect(r.ok).toBe(false)
})
it("decompresses a compressed mxfile into plain XML pages", () => {
const r = parseDrawioFileContent(COMPRESSED_MXFILE)
expect(r.ok).toBe(true)
if (r.ok) {
expect(r.xml).toContain(" {
const mixed = `${MODEL_XML}${drawioCompress(MODEL_XML)}`
const r = parseDrawioFileContent(mixed)
expect(r.ok).toBe(true)
if (r.ok) {
const doc = new DOMParser().parseFromString(r.xml, "text/xml")
const diagrams = Array.from(
doc.querySelectorAll("diagram"),
) as Element[]
expect(diagrams).toHaveLength(2)
for (const d of diagrams) {
expect(d.querySelector("mxGraphModel")).not.toBeNull()
}
}
})
it("keeps empty pages as-is", () => {
const withEmpty = `${MODEL_XML}`
const r = parseDrawioFileContent(withEmpty)
expect(r).toEqual({ ok: true, xml: withEmpty })
})
it("rejects empty files", () => {
const r = parseDrawioFileContent(" ")
expect(r.ok).toBe(false)
})
it("rejects non-drawio content", () => {
const r = parseDrawioFileContent("")
expect(r.ok).toBe(false)
if (!r.ok) expect(r.error).toContain("Not a draw.io file")
})
it("rejects a page whose content is neither XML nor compressed", () => {
const bad = `!!! not a diagram !!!`
const r = parseDrawioFileContent(bad)
expect(r.ok).toBe(false)
if (!r.ok) expect(r.error).toContain('"Broken"')
})
})