Build and publish Eldorado documentation / build (pull_request) Successful in 41s
57 lines
3.6 KiB
JavaScript
57 lines
3.6 KiB
JavaScript
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFileSync} from 'node:fs';
|
|
const read = p => readFileSync(p, 'utf8');
|
|
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
|
|
|
test('every strategy page leads with a compact diagram story and closes its references', () => {
|
|
for (const {id} of model.pages) {
|
|
const page = read(`docs/strategy/${id === 'measurement' ? 'measurement/index' : id}.mdx`);
|
|
const narrative = page.split('<div className="strategy-content">')[1].replace(/<details>[\s\S]*?<\/details>/g, '');
|
|
assert.equal((narrative.match(/<ArchifyDiagram /g) || []).length, id === 'roadmap' ? 3 : 1, id);
|
|
assert(narrative.includes(' story />'), id);
|
|
assert(!page.includes('<details>') || page.indexOf(' story />') < page.indexOf('<details>'), id);
|
|
assert(!/<details\s+open/.test(page), id);
|
|
assert.equal((page.match(/<details>/g) || []).length, (page.match(/<\/details>/g) || []).length, id);
|
|
assert.equal((narrative.match(/^## /gm) || []).length, id === 'measurement' ? 5 : id === 'roadmap' ? 4 : 1, id);
|
|
assert((narrative.match(/^- /gm) || []).length <= 3, id);
|
|
assert(narrative.includes('**Next:**'), id);
|
|
assert(!narrative.includes('| ---'), id);
|
|
const words = narrative.replace(/<[^>]*>/g, '').trim().split(/\s+/).length;
|
|
assert(words <= (id === 'measurement' ? 1500 : id === 'roadmap' ? 600 : 200), `${id}: ${words} default narrative words`);
|
|
}
|
|
});
|
|
|
|
test('mobile story diagrams preserve the same nodes and directed relationships', () => {
|
|
for (const {id} of model.pages) {
|
|
const page = read(`docs/strategy/${id === 'measurement' ? 'measurement/index' : id}.mdx`);
|
|
const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1];
|
|
if (name === 'strategy-roadmap') {
|
|
const desktop = JSON.parse(read(`diagrams/${name}.workflow.json`));
|
|
const mobile = JSON.parse(read(`diagrams/${name}-mobile.workflow.json`));
|
|
const semantic = d => ({nodes:d.nodes.map(({col,yOffset,...n}) => n), edges:d.edges.map(({fromSide,toSide,...e}) => e)});
|
|
assert.deepEqual(semantic(desktop), semantic(mobile));
|
|
continue;
|
|
}
|
|
const desktop = JSON.parse(read(`diagrams/${name}.architecture.json`));
|
|
const mobile = JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
|
|
assert(desktop.components.length >= 5, name);
|
|
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,route,via,labelAt,...e})=>e)});
|
|
assert.deepEqual(semantic(desktop), semantic(mobile), name);
|
|
assert(desktop.connections.every(e => (e.label || e.id.startsWith('govern-') || /^strategy-(governance|quality|adoption|measurement|maintenance)$/.test(name)) && e.from !== e.to), name);
|
|
assert.equal(desktop.meta.legend.mode, 'hidden');
|
|
}
|
|
});
|
|
|
|
test('all sixteen exact KPI formulas remain reachable in the linked reference', () => {
|
|
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
|
assert.equal(manifest.metrics.length, 16);
|
|
for (const metric of model.kpis) {
|
|
const entry = manifest.metrics.find(m => m.title === metric.name);
|
|
assert(read('docs/strategy/measurement/index.mdx').includes(`./${entry.oldAnchor}.mdx`));
|
|
const section = read(`docs/strategy/${entry.docId}.mdx`);
|
|
assert(section, metric.name);
|
|
for (const label of ['Numerator','Denominator','Expression','Aggregation','Unit','Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert(section.includes(`| ${label} |`), `${metric.name}: ${label}`);
|
|
}
|
|
});
|