docs: present AI strategy as a diagram-first story
Build and publish Eldorado documentation / build (pull_request) Successful in 40s
Build and publish Eldorado documentation / build (pull_request) Successful in 40s
This commit is contained in:
1 parent
7f40de708c
commit
794f2aa2d6
30 files changed
+2496
-4
No files matched your search
@@ -0,0 +1,43 @@
|
||||
const {chromium}=require('playwright');
|
||||
const assert=require('node:assert/strict');
|
||||
const fs=require('node:fs');
|
||||
(async()=>{
|
||||
const base=process.argv[2]||'http://127.0.0.1:4173';
|
||||
const label=process.argv[3]||'accepted';
|
||||
const browser=await chromium.launch({headless:true,executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE,args:['--no-sandbox']});
|
||||
const results=[];fs.mkdirSync(`.cache/story-${label}`,{recursive:true});
|
||||
try{
|
||||
for(const width of [1440,390]){
|
||||
const context=await browser.newContext({viewport:{width,height:1000}});
|
||||
const page=await context.newPage();
|
||||
for(const id of ['index','target-operating-model','skills-governance','skills-quality','skills-adoption','measurement','skills-maintenance','roadmap']){
|
||||
const response=await page.goto(`${base}/eldorado-v1/documentation/strategy/${id==='index'?'':id+'/'}`,{waitUntil:'networkidle'});assert.equal(response.status(),200);
|
||||
const panel=page.locator('.archify-panel--story');
|
||||
const iframe=panel.locator(width===390?'.story-mobile':'.story-desktop');await iframe.scrollIntoViewIfNeeded();
|
||||
const frame=await (await iframe.elementHandle()).contentFrame();await frame.locator('svg[role="img"]').waitFor();
|
||||
const geometry=await frame.locator('svg[role="img"]').evaluate(svg=>{
|
||||
const nodes=[...svg.querySelectorAll('[data-node-id]')].map(n=>{const r=n.getBoundingClientRect();return {id:n.id,x:r.x,y:r.y,right:r.right,bottom:r.bottom};});
|
||||
return {width:innerWidth,height:innerHeight,nodes,svg:svg.getBoundingClientRect().toJSON(),minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n=>parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))};
|
||||
});
|
||||
assert(geometry.nodes.length>=5 && geometry.nodes.length<=7,id);
|
||||
for(const n of geometry.nodes) assert(n.x>=0 && n.y>=0 && n.right<=geometry.width+1 && n.bottom<=geometry.height+1,`${id} ${width} clipped ${JSON.stringify(n)} / ${geometry.height}`);
|
||||
const data=await page.locator('.strategy-content').evaluate(el=>({words:el.innerText.trim().split(/\s+/).length,overflow:document.documentElement.scrollWidth>innerWidth,openDetails:el.querySelectorAll('details[open]').length}));
|
||||
assert(data.words<=200,id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id);
|
||||
await page.evaluate(()=>scrollTo(0,0));await page.screenshot({path:`.cache/story-${label}/${width}-${id}.png`,fullPage:true});
|
||||
const opener=panel.getByRole('button',{name:/^Expand /});await opener.click();
|
||||
const close=panel.getByRole('button',{name:'Close full-screen diagram',exact:true});await close.waitFor({state:'visible'});
|
||||
assert.equal(await close.innerText(),'×');assert(await close.evaluate(n=>n===document.activeElement));
|
||||
const box=await close.boundingBox();assert.equal(box.width,44);assert.equal(box.height,44);
|
||||
await close.click();assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
await opener.click();await close.waitFor({state:'visible'});await page.keyboard.press('Escape');await page.waitForFunction(()=>!document.querySelector('.archify-panel--story dialog').open);assert(await opener.evaluate(n=>n===document.activeElement));
|
||||
const summary=page.locator('.strategy-content > details > summary').first();await summary.click();assert(await summary.evaluate(n=>n.parentElement.open));await summary.click();
|
||||
results.push({id,width,...data,geometry,modalClick:true,modalEscape:true,focusRestored:true,details:true});fs.writeFileSync(`.cache/story-${label}/results.json`,JSON.stringify(results,null,2));
|
||||
}
|
||||
await page.goto(`${base}/eldorado-v1/documentation/strategy/measurement/#validated-task-success`,{waitUntil:'networkidle'});
|
||||
const heading=page.locator('#validated-task-success');await heading.waitFor({state:'visible'});
|
||||
assert(await heading.evaluate(n=>n.closest('details').open),'hash should open metric reference');
|
||||
await context.close();
|
||||
}
|
||||
console.log(`PASS ${results.length} desktop/mobile cases, clipping, default word count, details, modal click/Escape/focus and KPI hash navigation`);
|
||||
} finally {await browser.close();}
|
||||
})().catch(e=>{console.error(e);process.exitCode=1});
|
||||
@@ -0,0 +1,48 @@
|
||||
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.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, 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 <= 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 <= 7, name);
|
||||
const semantic = d => ({nodes:d.components.map(({pos,size,...n})=>n),edges:d.connections.map(({fromSide,toSide,...e})=>e)});
|
||||
assert.deepEqual(semantic(desktop), semantic(mobile), name);
|
||||
assert(desktop.connections.every(e => e.label && e.from !== e.to), name);
|
||||
assert.equal(desktop.meta.legend.mode, 'hidden');
|
||||
}
|
||||
});
|
||||
|
||||
test('all sixteen exact KPI formulas remain reachable in the closed reference', () => {
|
||||
const page = read('docs/strategy/measurement.mdx');
|
||||
const contracts = page.split('<summary>All 16 KPI contracts')[1].split('</details>')[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}`);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user