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<=(['index','target-operating-model'].includes(id)?18: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<=(id==='measurement'?1100:id==='roadmap'?600:200),id);assert(!data.overflow,id);assert.equal(data.openDetails,0,id); await page.evaluate(()=>scrollTo({top:0,behavior:'instant'}));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();await panel.locator('dialog iframe').waitFor({state:'detached'});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); // Native close clears open before the queued React onClose restores focus. // Wait for its unmount before focusing the next keyboard interaction target. await panel.locator('dialog iframe').waitFor({state:'detached'});assert(await opener.evaluate(n=>n===document.activeElement)); if(id !== 'measurement') { const summary=page.locator('.strategy-content > details > summary').first(); await summary.focus();await page.keyboard.press('Enter'); await page.waitForFunction(()=>document.querySelector('.strategy-content > details').open); await page.keyboard.press('Enter'); } results.push({id,width,...data,geometry,modalClick:true,modalEscape:true,focusRestored:true,details:id!=='measurement'});fs.writeFileSync(`.cache/story-${label}/results.json`,JSON.stringify(results,null,2)); } await page.goto(`${base}/eldorado-v1/documentation/strategy/reference/measurement-contracts/#validated-task-success`,{waitUntil:'networkidle'}); const heading=page.locator('#validated-task-success');await heading.waitFor({state:'visible'}); assert.equal(await page.locator('.strategy-content details').count(),0,'reference is directly readable'); 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});