Build and publish Eldorado documentation / build (pull_request) Successful in 41s
61 lines
4.8 KiB
JavaScript
61 lines
4.8 KiB
JavaScript
import {test} from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import {readFileSync, mkdtempSync, rmSync} from 'node:fs';
|
||
import {tmpdir} from 'node:os';
|
||
import {join} from 'node:path';
|
||
import {execFileSync} from 'node:child_process';
|
||
import {skillsViewer,isSkillsStory} from './skills-viewer.mjs';
|
||
const read = p => readFileSync(p,'utf8');
|
||
const topics = ['governance','quality','adoption','measurement','maintenance'];
|
||
test('all six Skills Adoption pages account for exactly five diagrams and ten sources',()=>{
|
||
let count=0;
|
||
for(const route of ['stage-01-skills-adoption',...topics.map(t=>t==='measurement'?t:`skills-${t}`)]){
|
||
const diagrams=[...read(`docs/strategy/${route === 'measurement' ? 'measurement/index' : route}.mdx`).matchAll(/<ArchifyDiagram name="([^"]+)"/g)];
|
||
assert.equal(diagrams.length,route.startsWith('stage-')?0:1);
|
||
for(const [,name] of diagrams){assert(isSkillsStory(name));for(const suffix of ['','-mobile'])JSON.parse(read(`diagrams/${name}${suffix}.architecture.json`));count++;}
|
||
}
|
||
assert.equal(count,5);assert(!isSkillsStory('strategy-target'));assert(!isSkillsStory('strategy-roadmap'));
|
||
});
|
||
for(const topic of topics) test(`${topic}: rich native source, wide desktop, mobile parity and checked adapter`,()=>{
|
||
const name=`strategy-${topic}`;const desktop=JSON.parse(read(`diagrams/${name}.architecture.json`));
|
||
const mobile=JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
|
||
const semantic = d=>d.components.map(({pos,size,...n})=>n);
|
||
assert.deepEqual(semantic(desktop),semantic(mobile));
|
||
assert(new Set(desktop.components.map(n=>n.pos[0])).size>1);
|
||
assert.equal(new Set(mobile.components.map(n=>n.pos[0])).size,1);
|
||
for(const n of desktop.components){assert(n.tag);assert(n.sublabel);assert(n.sublabel.split('\n').length<=4);}
|
||
const dir=mkdtempSync(join(tmpdir(),'skills-viewer-'));
|
||
try{
|
||
const path=join(dir,'native.html');
|
||
execFileSync(process.execPath,['vendor/archify/renderers/architecture/render-architecture.mjs',`diagrams/${name}.architecture.json`,path]);
|
||
const native=read(path);const html=skillsViewer(native,desktop);
|
||
assert.equal((html.match(/<g\b[^>]*data-node-id=/g)||[]).length,desktop.components.length);
|
||
assert.equal((html.match(/<text data-node-label=/g)||[]).length,0); // Adapter uses explicit position before semantic attributes.
|
||
assert.equal((html.match(/data-node-label=""/g)||[]).length,desktop.components.length);
|
||
assert(html.includes('eldorado-skills-typography'));
|
||
assert.throws(()=>skillsViewer(native.replace('data-node-id="'+desktop.components[0].id+'"','data-node-id="missing"'),desktop));
|
||
const bad=structuredClone(desktop);bad.components[0].sublabel='';assert.throws(()=>skillsViewer(native,bad));
|
||
}finally{rmSync(dir,{recursive:true,force:true});}
|
||
});
|
||
test('domain contracts retain human authority, honest measures and Delivery-first rollout',()=>{
|
||
const text=t=>JSON.stringify(JSON.parse(read(`diagrams/strategy-${t}.architecture.json`)));
|
||
assert(text('governance').includes('Author is not sole approver'));
|
||
assert(text('quality').includes('Critical effect blocks'));
|
||
assert(text('adoption').includes('Delivery first')&&text('adoption').includes('Later order undecided'));
|
||
assert(text('adoption').includes('No quotas or rankings'));
|
||
for(const marker of ['Tracker + acceptance','Invoices + review minutes','Changes + defects','Anonymous 1–5 survey','Missing buckets = partial','Zero denominator = N/A'])assert(text('measurement').includes(marker),marker);
|
||
assert(text('maintenance').includes('No automatic reinstatement'));
|
||
});
|
||
test('topic compositions explain distinct relationships rather than a fixed card count',()=>{
|
||
const spec=t=>JSON.parse(read(`diagrams/strategy-${t}.architecture.json`));
|
||
const has=(d,a,b)=>assert(d.connections.some(e=>e.from===a&&e.to===b),`${a} → ${b}`);
|
||
const g=spec('governance');const steps=g.components.filter(n=>/^0[1-6]/.test(n.label));
|
||
assert.equal(steps.length,6);
|
||
for(let i=1;i<steps.length;i++){assert(steps[i].pos[0]>steps[i-1].pos[0]);assert(steps[i].pos[1]>steps[i-1].pos[1]);has(g,steps[i-1].id,steps[i].id);}
|
||
has(g,'approve','owner');has(g,'distribute','withdraw');
|
||
const q=spec('quality');for(const id of ['selection','safety','artifact','outcome'])has(q,id,'gate');has(q,'gate','accept');has(q,'gate','rework');
|
||
const a=spec('adoption');for(const [x,y] of [['human','agent'],['agent','human'],['agent','learn'],['learn','delivery'],['learn','expand'],['human','expand']])has(a,x,y);
|
||
const m=spec('measurement');for(const id of ['success','quality','cost','confidence']){has(m,id+'-source',id);has(m,id,'interpret');}
|
||
const c=spec('maintenance');for(const [x,y] of [['observe','triage'],['triage','change'],['change','validate'],['validate','release'],['release','observe'],['triage','safe'],['safe','observe'],['triage','retire'],['triage','contain'],['contain','change']])has(c,x,y);
|
||
});
|