clone

a browser-first diagram editor with live svg previews, local drafts and encrypted, accountless sharing

main
diagramzip / renderers / scripts / smoke-units.mjs
smoke-units.mjs 10.6K
1import { readFile } from 'node:fs/promises'2import { resolve } from 'node:path'34const diagramDirectory = resolve(import.meta.dirname, '../../examples/diagrams')5const diagrams = {6 plantuml: 'architecture.puml',7 mermaid: 'contribute.mmd',8 graphviz: 'hello.dot',9 d2: 'connections.d2',10 c4plantuml: 'banking-system.puml',11 blockdiag: 'kroki.diag',12 seqdiag: 'sequence.diag',13 actdiag: 'actions.diag',14 nwdiag: 'network.diag',15 packetdiag: 'packet.diag',16 rackdiag: 'rack.diag',17 bpmn: 'example.bpmn',18 bytefield: 'bytefield.bf',19 dbml: 'dbml.dbml',20 diagramsnet: 'diagramsnet-venn.xml',21 ditaa: 'components.ditaa',22 erd: 'schema.erd',23 excalidraw: 'venn.excalidraw',24 goat: 'components.goat',25 nomnoml: 'pirate.nomnoml',26 pikchr: 'diamond.pikchr',27 structurizr: 'gettingstarted.structurizr',28 svgbob: 'cloud.bob',29 symbolator: 'component.sv',30 tikz: 'periodic-table.tex',31 squaring: 'order-nine.squaring',32 trn: 'zenith.trn',33 umlet: 'umlet.xml',34 vega: 'bar-chart.vega',35 vegalite: 'discretizing-scale.vlite',36 wavedrom: 'wavedrom.json5',37 wireviz: 'wireviz.yaml',38}3940const sharedUnits = {41 plantuml: 'plantuml-family',42 c4plantuml: 'plantuml-family',43 blockdiag: 'blockdiag-family',44 seqdiag: 'blockdiag-family',45 actdiag: 'blockdiag-family',46 nwdiag: 'blockdiag-family',47 packetdiag: 'blockdiag-family',48 rackdiag: 'blockdiag-family',49 graphviz: 'graphviz-family',50 dbml: 'graphviz-family',51 erd: 'graphviz-family',52 vega: 'vega-family',53 vegalite: 'vega-family',54 wireviz: 'wireviz',55 structurizr: 'structurizr',56 svgbob: 'svgbob-family',57 ditaa: 'svgbob-family',58}5960const pythonEngines = new Set(['blockdiag', 'seqdiag', 'actdiag', 'nwdiag', 'packetdiag', 'rackdiag'])61const graphvizEngines = new Set(['graphviz', 'erd', 'dbml'])62const pikchrEngines = new Set(['pikchr'])63const svgbobEngines = new Set(['svgbob', 'ditaa'])64const goatEngines = new Set(['goat'])65const wirevizEngines = new Set(['wireviz'])66const plantumlEngines = new Set(['plantuml', 'c4plantuml'])67const structurizrEngines = new Set(['structurizr'])68const d2Engines = new Set(['d2'])69const symbolatorEngines = new Set(['symbolator'])70const umletEngines = new Set(['umlet'])71const browserRunEngines = new Set(['mermaid', 'diagramsnet'])72const bpmnEngines = new Set(['bpmn'])73const excalidrawEngines = new Set(['excalidraw'])74const tikzEngines = new Set(['tikz'])7576async function smoke([engine, filename]) {77 const source = await readFile(resolve(diagramDirectory, filename), 'utf8')78 const endpoint = `https://${engine}.render.diagram.zip/v1/svg`79 const response = await fetch(endpoint, {80 method: 'POST',81 headers: { Accept: 'image/svg+xml', 'Content-Type': 'application/json' },82 body: JSON.stringify({83 source,84 format: 'svg',85 options: {},86 metadata: { title: '', description: '' },87 presentation: { background: '', padding: 0, frame: false },88 }),89 })90 const body = await response.text()91 if (!response.ok) throw new Error(`${engine}: HTTP ${response.status}: ${body.slice(0, 240)}`)92 if (!/<svg[\s>]/i.test(body)) throw new Error(`${engine}: response is not SVG`)93 const expectedUnit = sharedUnits[engine] ?? engine94 if (response.headers.get('X-Diagram-Unit') !== expectedUnit) {95 throw new Error(`${engine}: expected unit ${expectedUnit}, received ${response.headers.get('X-Diagram-Unit')}`)96 }97 const pipeline = response.headers.get('X-Diagram-Pipeline')98 const expectedPipeline = engine === 'vegalite'99 ? `${expectedUnit},vega`100 : engine === 'graphviz'101 ? `${expectedUnit},graphviz`102 : engine === 'erd'103 ? `${expectedUnit},erd,graphviz`104 : engine === 'dbml'105 ? `${expectedUnit},dbml,graphviz`106 : engine === 'wireviz'107 ? `${expectedUnit},graphviz-family,graphviz`108 : engine === 'structurizr'109 ? `${expectedUnit},plantuml-family,plantuml`110 : engine === 'ditaa'111 ? `${expectedUnit},svgbob`112 : expectedUnit113 if (pipeline !== expectedPipeline) {114 throw new Error(`${engine}: unexpected pipeline ${pipeline}`)115 }116 if (browserRunEngines.has(engine) && response.headers.get('X-Diagram-Renderer') !== 'browser-run') {117 throw new Error(`${engine}: expected browser-run renderer, received ${response.headers.get('X-Diagram-Renderer')}`)118 }119 if (bpmnEngines.has(engine)) {120 if (response.headers.get('X-Diagram-Renderer') !== 'edge-js') throw new Error(`${engine}: expected edge-js renderer, received ${response.headers.get('X-Diagram-Renderer')}`)121 if (!response.headers.get('X-Renderer-Build')?.startsWith('bpmn-direct-svg-')) throw new Error(`${engine}: unexpected BPMN Worker build ${response.headers.get('X-Renderer-Build')}`)122 }123 if (excalidrawEngines.has(engine)) {124 if (response.headers.get('X-Diagram-Renderer') !== 'edge-js') throw new Error(`${engine}: expected edge-js renderer, received ${response.headers.get('X-Diagram-Renderer')}`)125 if (!response.headers.get('X-Renderer-Build')?.startsWith('excalidraw-0.18.1-edge-dom-')) throw new Error(`${engine}: unexpected Excalidraw Worker build ${response.headers.get('X-Renderer-Build')}`)126 }127 if (tikzEngines.has(engine)) {128 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)129 if (!response.headers.get('X-Renderer-Build')?.startsWith('tikzjax-1.0.63-edge-core-')) throw new Error(`${engine}: unexpected TikZ Worker build ${response.headers.get('X-Renderer-Build')}`)130 }131 if (pythonEngines.has(engine)) {132 if (response.headers.get('X-Diagram-Renderer') !== 'edge-python') {133 throw new Error(`${engine}: expected edge-python renderer, received ${response.headers.get('X-Diagram-Renderer')}`)134 }135 if (!response.headers.get('X-Renderer-Build')?.startsWith('blockdiag-3.4.2-family-python-')) {136 throw new Error(`${engine}: unexpected Python Worker build ${response.headers.get('X-Renderer-Build')}`)137 }138 }139 if (graphvizEngines.has(engine)) {140 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') {141 throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)142 }143 if (!response.headers.get('X-Renderer-Build')?.startsWith('graphviz-15.1.1-family-edge-wasm-')) {144 throw new Error(`${engine}: unexpected GraphViz-family Worker build ${response.headers.get('X-Renderer-Build')}`)145 }146 }147 if (pikchrEngines.has(engine)) {148 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') {149 throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)150 }151 if (!response.headers.get('X-Renderer-Build')?.startsWith('pikchr-85e65b9686-edge-wasm-')) {152 throw new Error(`${engine}: unexpected Pikchr Worker build ${response.headers.get('X-Renderer-Build')}`)153 }154 }155 if (svgbobEngines.has(engine)) {156 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') {157 throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)158 }159 if (!response.headers.get('X-Renderer-Build')?.startsWith('svgbob-0.7.6-ditaa-translation-')) {160 throw new Error(`${engine}: unexpected Svgbob Worker build ${response.headers.get('X-Renderer-Build')}`)161 }162 }163 if (goatEngines.has(engine)) {164 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)165 if (!response.headers.get('X-Renderer-Build')?.startsWith('goat-0.5.1-edge-wasm-')) throw new Error(`${engine}: unexpected GoAT Worker build ${response.headers.get('X-Renderer-Build')}`)166 }167 if (wirevizEngines.has(engine)) {168 if (response.headers.get('X-Diagram-Renderer') !== 'edge-python') {169 throw new Error(`${engine}: expected edge-python renderer, received ${response.headers.get('X-Diagram-Renderer')}`)170 }171 if (!response.headers.get('X-Renderer-Build')?.startsWith('wireviz-0.3.2-python-dot-')) {172 throw new Error(`${engine}: unexpected WireViz Worker build ${response.headers.get('X-Renderer-Build')}`)173 }174 }175 if (plantumlEngines.has(engine)) {176 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') {177 throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)178 }179 if (!response.headers.get('X-Renderer-Build')?.startsWith('plantuml-family-edge-wasm-')) {180 throw new Error(`${engine}: unexpected PlantUML-family Worker build ${response.headers.get('X-Renderer-Build')}`)181 }182 }183 if (structurizrEngines.has(engine)) {184 if (response.headers.get('X-Diagram-Renderer') !== 'edge-js') throw new Error(`${engine}: expected edge-js renderer, received ${response.headers.get('X-Diagram-Renderer')}`)185 if (!response.headers.get('X-Renderer-Build')?.startsWith('structurizr-6.2.2-plantuml-translation-')) throw new Error(`${engine}: unexpected Structurizr Worker build ${response.headers.get('X-Renderer-Build')}`)186 }187 if (d2Engines.has(engine)) {188 if (response.headers.get('X-Diagram-Renderer') !== 'edge-wasm') throw new Error(`${engine}: expected edge-wasm renderer, received ${response.headers.get('X-Diagram-Renderer')}`)189 if (!response.headers.get('X-Renderer-Build')?.startsWith('d2-0.7.1-dagre-wasm-')) throw new Error(`${engine}: unexpected D2 Worker build ${response.headers.get('X-Renderer-Build')}`)190 }191 if (symbolatorEngines.has(engine)) {192 if (response.headers.get('X-Diagram-Renderer') !== 'edge-python') throw new Error(`${engine}: expected edge-python renderer, received ${response.headers.get('X-Diagram-Renderer')}`)193 if (!response.headers.get('X-Renderer-Build')?.startsWith('symbolator-python-')) throw new Error(`${engine}: unexpected Symbolator Worker build ${response.headers.get('X-Renderer-Build')}`)194 }195 if (umletEngines.has(engine)) {196 if (response.headers.get('X-Diagram-Renderer') !== 'edge-js') throw new Error(`${engine}: expected edge-js renderer, received ${response.headers.get('X-Diagram-Renderer')}`)197 if (!response.headers.get('X-Renderer-Build')?.startsWith('umlet-direct-svg-')) throw new Error(`${engine}: unexpected UMLet Worker build ${response.headers.get('X-Renderer-Build')}`)198 }199 return `${engine.padEnd(10)} ${response.headers.get('X-Diagram-Cache')?.padEnd(4)} ${body.length} bytes`200}201202const entries = Object.entries(diagrams)203const results = []204for (let index = 0; index < entries.length; index += 4) {205 results.push(...await Promise.all(entries.slice(index, index + 4).map(smoke)))206}207for (const result of results) console.log(result)208console.log(`${results.length}/${results.length} catalog engines passed structural unit smoke`)