Build and publish Eldorado documentation / build (pull_request) Successful in 40s
50 lines
3.1 KiB
JavaScript
50 lines
3.1 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}.mdx`);
|
|
const narrative = page.split('<div className="strategy-content">')[1].replace(/<details>[\s\S]*?<\/details>/g, '');
|
|
assert.equal((narrative.match(/<ArchifyDiagram /g) || []).length, 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' ? 4 : id === 'roadmap' ? 5 : 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' ? 1100 : 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}.mdx`);
|
|
const name = /<ArchifyDiagram name="([^"]+)"[^>]+ story/.exec(page)[1];
|
|
const desktop = JSON.parse(read(`diagrams/${name}.architecture.json`));
|
|
const mobile = JSON.parse(read(`diagrams/${name}-mobile.architecture.json`));
|
|
assert(desktop.components.length >= 5 && desktop.components.length <= (name === 'strategy-target' ? 18 : 7), name);
|
|
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,via,labelAt,...e})=>e)});
|
|
assert.deepEqual(semantic(desktop), semantic(mobile), name);
|
|
assert(desktop.connections.every(e => (e.label || e.id.startsWith('govern-')) && e.from !== e.to), name);
|
|
assert.equal(desktop.meta.legend.mode, 'hidden');
|
|
}
|
|
});
|
|
|
|
test('all sixteen exact KPI formulas remain reachable in the linked reference', () => {
|
|
assert(read('docs/strategy/measurement.mdx').includes('./reference/measurement-contracts.mdx'));
|
|
const page = read('docs/strategy/reference/measurement-contracts.mdx');
|
|
const contracts = page.split('## Metric contracts')[1].split('## Run the synthetic')[0];
|
|
assert.equal((contracts.match(/^### /gm) || []).length, 16);
|
|
for (const metric of model.kpis) {
|
|
const section = contracts.split(`### ${metric.name}\n`)[1]?.split('\n### ')[0];
|
|
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}`);
|
|
}
|
|
});
|