Build and publish Eldorado documentation / build (pull_request) Successful in 46s
46 lines
3.2 KiB
JavaScript
46 lines
3.2 KiB
JavaScript
const {chromium}=require('playwright');
|
|
const fs=require('node:fs');
|
|
const path=require('node:path');
|
|
const assert=require('node:assert/strict');
|
|
(async()=>{
|
|
const dir=process.argv[2]||'.cache/skills-candidate';
|
|
const browser=await chromium.launch({executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});
|
|
const results=[];
|
|
try {
|
|
for(const topic of ['measurement','baseline','governance','quality','adoption','maintenance']) for(const width of [1440,1024,390,320]){
|
|
const spec=JSON.parse(fs.readFileSync(`diagrams/strategy-${topic}${width<=1100?'-mobile':''}.architecture.json`));
|
|
const page=await browser.newPage({viewport:{width:1200,height:1000}});
|
|
await page.goto('file://'+path.resolve(`${dir}/${topic}-${width}.svg`));
|
|
const measured=await page.locator('svg').evaluate(svg=>{
|
|
const v=svg.viewBox.baseVal;const issues=[];
|
|
for(const el of svg.querySelectorAll('[data-node-id],path[data-edge-id],g[data-edge-id]')){
|
|
const b=el.getBBox();if(b.x<v.x-1||b.y<v.y-1||b.x+b.width>v.x+v.width+1||b.y+b.height>v.y+v.height+1)issues.push(el.getAttribute('data-node-id')||el.getAttribute('data-edge-id'));
|
|
}
|
|
// Measure the whole rendered label group, including its opaque mask:
|
|
// text presence alone cannot detect one label hiding another.
|
|
const labels=[...svg.querySelectorAll('g[data-edge-id]')].filter(el=>el.querySelector('text')).map(el=>({id:el.dataset.edgeId,box:el.getBoundingClientRect()}));
|
|
const labelOverlaps=[];
|
|
for(let i=0;i<labels.length;i++)for(let j=i+1;j<labels.length;j++){
|
|
const a=labels[i],b=labels[j];
|
|
if(Math.min(a.box.right,b.box.right)>Math.max(a.box.left,b.box.left)&&Math.min(a.box.bottom,b.box.bottom)>Math.max(a.box.top,b.box.top))labelOverlaps.push([a.id,b.id]);
|
|
}
|
|
return {labelOverlaps,viewBox:[v.width,v.height],nodes:[...svg.querySelectorAll('[data-node-id]')].map(n=>n.dataset.nodeId),edges:[...svg.querySelectorAll('path[data-edge-id]')].map(n=>n.dataset.edgeId),text:svg.textContent,issues};
|
|
});
|
|
assert.deepEqual(measured.viewBox,spec.meta.viewBox);
|
|
assert.deepEqual(measured.nodes.sort(),spec.components.map(n=>n.id).sort());
|
|
assert.deepEqual(measured.edges.sort(),spec.connections.map(e=>e.id).sort());
|
|
assert.deepEqual(measured.issues,[]);
|
|
assert.deepEqual(measured.labelOverlaps,[],`${topic}-${width}: rendered edge labels overlap`);
|
|
for(const n of spec.components){assert(measured.text.includes(n.label));assert(measured.text.includes(n.tag));for(const line of n.sublabel.split('\n'))assert(measured.text.includes(line));}
|
|
for(const e of spec.connections)if(e.label)assert(measured.text.includes(e.label));
|
|
if(width===1440){
|
|
await page.setViewportSize({width:spec.meta.viewBox[0],height:spec.meta.viewBox[1]});
|
|
await page.screenshot({path:`${dir}/${topic}-standalone-export.png`});
|
|
}
|
|
results.push({topic,width,nodes:measured.nodes.length,edges:measured.edges.length,complete:true});await page.close();
|
|
}
|
|
fs.writeFileSync(`${dir}/export-results.json`,JSON.stringify(results,null,2));
|
|
console.log(`PASS ${results.length} standalone SVGs: exact graph, text, full-canvas containment and non-overlapping edge labels`);
|
|
}finally{await browser.close();}
|
|
})().catch(e=>{console.error(e);process.exitCode=1});
|