docs: start roadmap with code and process assessment
Build and publish Eldorado documentation / build (pull_request) Successful in 40s

This commit is contained in:
jarvis-at-skic committed 2026-10-05 18:50:28 +00:00
1 parent b679e6b2b5
commit 1de7d16d09
9 files changed
+243 -124

No files matched your search

+86
View File
@@ -0,0 +1,86 @@
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 output = `.cache/roadmap-${process.argv[3] || 'local'}`;
fs.mkdirSync(output, {recursive:true});
const browser = await chromium.launch({headless:true, executablePath:process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, args:['--no-sandbox']});
const results = [];
try {
for (const width of [1440, 390, 320]) {
const context = await browser.newContext({viewport:{width,height:1000}, colorScheme:'light'});
const page = await context.newPage();
const errors = [];
page.on('pageerror', error => errors.push(error.message));
const response = await page.goto(`${base}/eldorado-v1/documentation/strategy/roadmap/`, {waitUntil:'networkidle'});
assert.equal(response.status(), 200);
assert.equal(await page.locator('h1').innerText(), 'Roadmap');
const headings = page.locator('.strategy-content > h2');
assert.deepEqual((await headings.allTextContents()).map(s => s.replace(/\u200b/g, '')), ['1. Understand code quality and delivery','2. Fix critical readiness gaps','3. Run a bounded pilot','4. Expand only on evidence','5. Sustain and improve']);
const text = await page.locator('.strategy-content').innerText();
for (const marker of ['baseline findings', 'process map', 'prioritized gaps', 'alongside the pilot', 'Recommended sequence']) assert(text.includes(marker), marker);
assert(!text.includes('Supporting gate evidence and hold conditions\n\nThese are'));
if (width < 700) await page.getByRole('button', {name:'Toggle navigation bar'}).click();
const menu = page.locator('.theme-doc-sidebar-menu .menu__link').filter({visible:true});
await menu.first().waitFor({state:'visible'});
assert.deepEqual((await menu.allTextContents()).slice(0,2), ['Target','Roadmap']);
if (width < 700) await page.getByRole('button', {name:'Close navigation bar'}).click();
const panel = page.locator('.archify-panel--story');
const iframe = panel.locator(width > 700 ? '.story-desktop' : '.story-mobile');
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 => ({
nodes:[...svg.querySelectorAll('[data-node-id]')].map(n => ({id:n.dataset.nodeId,...n.getBoundingClientRect().toJSON()})),
width:innerWidth, height:innerHeight,
minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n => parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))
}));
assert.deepEqual(geometry.nodes.map(n => n.id), ['assessment','readiness','pilot','expansion','sustain']);
for (const n of geometry.nodes) assert(n.x >= 0 && n.y >= 0 && n.right <= geometry.width + 1 && n.bottom <= geometry.height + 1);
assert(geometry.minLabel >= 10, `readable node labels: ${geometry.minLabel}`);
await frame.locator('#btn-theme').click();
await page.waitForFunction(() => document.documentElement.dataset.theme === 'dark');
await frame.locator('#btn-theme').click();
await page.waitForFunction(() => document.documentElement.dataset.theme === 'light');
for (const preset of ['blueprint','classic']) {
await frame.locator('#btn-preset').click();
await frame.locator(`[data-preset-value="${preset}"]`).click();
assert.equal(await frame.locator('html').getAttribute('data-preset'), preset);
}
await frame.locator('#btn-export').click();
const [download] = await Promise.all([page.waitForEvent('download'), frame.locator('[data-format="svg"]').click()]);
assert.equal(await download.failure(), null);
await download.saveAs(`${output}/${width}.svg`);
assert(fs.readFileSync(`${output}/${width}.svg`, 'utf8').includes('Assess current state'));
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(), '×');
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));
assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth));
await page.evaluate(() => scrollTo({top:0, behavior:'instant'}));
await page.screenshot({path:`${output}/${width}-top.png`});
await headings.first().scrollIntoViewIfNeeded();
await page.screenshot({path:`${output}/${width}-assessment.png`});
await page.screenshot({path:`${output}/${width}-full.png`, fullPage:true});
await page.locator('.strategy-content summary').click();
assert(await page.locator('.strategy-content details').evaluate(n => n.open));
await page.locator('.strategy-content details p').last().waitFor({state:'visible'});
assert((await page.locator('.strategy-content details').innerText()).includes('exact-artifact approvals'));
const links = await page.locator('.strategy-content a').evaluateAll(nodes => nodes.filter(n => !n.classList.contains('hash-link')).map(n => n.href));
for (const href of [...new Set(links)]) {
const r = await page.goto(href, {waitUntil:'networkidle'}); assert.equal(r.status(), 200);
assert.equal(page.url(), href);
}
assert.deepEqual(errors, []);
results.push({width, geometry, links:links.length, controls:true, export:true, sidebar:true, visibleAssessment:true});
fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2));
await context.close();
}
console.log(`PASS ${results.length} Roadmap viewports: visible stages/outputs, sidebar, diagram geometry, controls, export and links`);
} finally {await browser.close();}
})().catch(error => {console.error(error); process.exitCode = 1;});