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/measurement-${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/measurement/`, {waitUntil:'networkidle'}); assert.equal(response.status(), 200); assert.equal(await page.locator('h1').innerText(), 'Skills Measurement'); assert((await page.title()).startsWith('Skills Measurement |')); assert.equal(await page.locator('.strategy-content details').count(), 0); assert.equal(await page.locator('.strategy-content h2').count(), 2); 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'}); const metrics = JSON.parse(fs.readFileSync('research/ai-adoption/measurement-migration.json','utf8')).metrics; assert.deepEqual(await menu.allTextContents(), ['Target','Roadmap','Stage - 01 - Skills Adoption','Measurement',...metrics.map(m => m.title),'Collection and safeguards','Run the synthetic measurement example','Baseline','Governance','Quality','Adoption','Maintenance','Stage - 02 - Autonomous Agent']); 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 => { const nodes = [...svg.querySelectorAll('[data-node-id]')].map(n => n.getBoundingClientRect().toJSON()); return {nodes, width:innerWidth, height:innerHeight, minLabel:Math.min(...[...svg.querySelectorAll('text[data-node-label]')].map(n => parseFloat(getComputedStyle(n).fontSize)*n.getScreenCTM().a))}; }); assert.equal(geometry.nodes.length, JSON.parse(fs.readFileSync('diagrams/strategy-measurement.architecture.json')).components.length); 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); const path = `${output}/${width}.svg`; await download.saveAs(path); const svg = fs.readFileSync(path, 'utf8'); assert(svg.includes('Available choices') && svg.includes('No mandatory collection')); 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 close.focus(); 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 page.locator('.strategy-content h2').nth(1).scrollIntoViewIfNeeded(); await page.screenshot({path:`${output}/${width}-pilot.png`}); await page.screenshot({path:`${output}/${width}-full.png`, fullPage:true}); const links = await page.locator('.strategy-content a[href*="/measurement/"]').evaluateAll(nodes => nodes.map(n => n.href)); for (const href of [...new Set(links)]) { const navigation = await page.goto(href, {waitUntil:'networkidle'}); if (navigation) assert.equal(navigation.status(), 200); assert.equal(page.url(), href); if (new URL(href).hash) await page.locator(new URL(href).hash).waitFor({state:'visible'}); } assert.equal(new Set(links.map(h => new URL(h).pathname)).size, 18); assert(!await page.evaluate(() => document.documentElement.scrollWidth > innerWidth)); assert.deepEqual(errors, []); results.push({width, geometry, links:links.length, title:true, sidebar:true, controls:true, export:true, reference:true}); fs.writeFileSync(`${output}/results.json`, JSON.stringify(results,null,2)); await context.close(); } console.log(`PASS ${results.length} Skills Measurement viewports: title/sidebar, optional registry, diagram geometry/controls/export, all reference links and no page errors`); } finally {await browser.close();} })().catch(error => {console.error(error); process.exitCode = 1;});