Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
46 lines
6.2 KiB
JavaScript
46 lines
6.2 KiB
JavaScript
import {build} from 'esbuild';
|
|
import {chromium, firefox} from 'playwright';
|
|
import {createServer} from 'node:http';
|
|
import {once} from 'node:events';
|
|
import {readFile, writeFile} from 'node:fs/promises';
|
|
import {createHash} from 'node:crypto';
|
|
import {fileURLToPath} from 'node:url';
|
|
import assert from 'node:assert/strict';
|
|
import {routeEscape} from './routing-transform.mjs';
|
|
const dir=fileURLToPath(new URL('.',import.meta.url));
|
|
const hash=x=>createHash('sha256').update(x).digest('hex');
|
|
const source=await readFile(dir+'node_modules/@radix-ui/react-dismissable-layer/dist/index.mjs','utf8');
|
|
assert.equal(hash(source),JSON.parse(await readFile(dir+'provenance.json')).inspected_files['@radix-ui/react-dismissable-layer/dist/index.mjs'].sha256);
|
|
const bundles=new Map();
|
|
for(const mode of ['development','production']) for(const variant of ['raw','routed']) {
|
|
const b=await build({entryPoints:[dir+'routing-fixture.jsx'],bundle:true,write:false,format:'iife',define:{'process.env.NODE_ENV':JSON.stringify(mode)},plugins:variant==='raw'?[]:[{name:'experimental-escape-router',setup(b){b.onLoad({filter:/@radix-ui\/react-dismissable-layer\/dist\/index\.mjs$/},()=>({contents:routeEscape(source),loader:'js',resolveDir:dir+'node_modules/@radix-ui/react-dismissable-layer/dist'}));}}]});
|
|
bundles.set(mode+'-'+variant,b.outputFiles[0].contents);
|
|
}
|
|
const server=createServer((req,res)=>{const u=new URL(req.url,'http://localhost');if(u.pathname==='/bundle.js'){res.setHeader('Content-Type','application/javascript');res.end(bundles.get(u.searchParams.get('key')));}else{res.setHeader('Content-Type','text/html');res.end(`<!doctype html><html lang="en"><title>Routing experiment</title><body><div id="root"></div><script src="/bundle.js?key=${u.searchParams.get('key')}"></script></body></html>`);}});
|
|
server.listen(0,'127.0.0.1');await once(server,'listening');
|
|
const results=[];
|
|
async function focused(page,id){await page.waitForFunction(id=>document.activeElement?.id===id,id,{timeout:1200});}
|
|
async function outer(page){await page.locator('#outer-trigger').focus();await page.keyboard.press('Enter');await focused(page,'inner-trigger');}
|
|
async function inner(page){await outer(page);await page.keyboard.press('Enter');await focused(page,'inner-close');}
|
|
const cases={
|
|
'ordinary':async p=>{await outer(p);await p.keyboard.press('Escape');await focused(p,'outer-trigger');assert.deepEqual(await p.evaluate(()=>window.routingObserved.escapes),['outer']);},
|
|
'nested-immediate':async p=>{await inner(p);await p.keyboard.press('Escape');await focused(p,'inner-trigger');assert.equal(await p.getByRole('dialog').count(),1);await p.keyboard.press('Escape');await focused(p,'outer-trigger');assert.deepEqual(await p.evaluate(()=>window.routingObserved.escapes),['inner','outer']);},
|
|
'cancel-inner':async p=>{await inner(p);await p.keyboard.press('Escape');assert.deepEqual(await p.evaluate(()=>window.routingObserved.escapes),['inner']);assert.equal(await p.getByRole('dialog', {includeHidden:true}).count(),2);await focused(p,'inner-close');},
|
|
'remove-trigger':async p=>{await inner(p);await p.keyboard.press('Tab');await focused(p,'remove-trigger');await p.keyboard.press('Enter');await focused(p,'outer-close');await p.keyboard.press('Escape');await focused(p,'outer-trigger');},
|
|
'remove-and-reopen':async p=>{await inner(p);await p.evaluate(()=>window.removeInner());await focused(p,'inner-trigger');await p.keyboard.press('Enter');await focused(p,'inner-close');await p.keyboard.press('Escape');await focused(p,'inner-trigger');assert.deepEqual(await p.evaluate(()=>window.routingObserved.escapes),['inner']);},
|
|
'ancestor-teardown':async p=>{await inner(p);await p.evaluate(()=>window.removeTask());await p.getByRole('dialog').waitFor({state:'detached'});await p.locator('#next').focus();await p.keyboard.press('Escape');assert.deepEqual(await p.evaluate(()=>window.routingObserved.escapes),[]);await focused(p,'next');}
|
|
};
|
|
try{
|
|
for(const [engine,launcher]of [['chromium',chromium],['firefox',firefox]]){
|
|
const browser=await launcher.launch({headless:true,...(engine==='chromium'?{executablePath:process.env.FEP_CHROMIUM_PATH}: {})});
|
|
try{for(const mode of ['development','production'])for(const variant of ['raw','routed'])for(const [name,run]of Object.entries(cases)){
|
|
const page=await browser.newPage();page.setDefaultTimeout(2000);const errors=[];page.on('pageerror',e=>errors.push(e.message));const r={engine,browser:browser.version(),mode,variant,case:name,status:'pass'};
|
|
try{await page.goto(`http://127.0.0.1:${server.address().port}/?key=${mode}-${variant}${name==='cancel-inner'?'&cancel=1':''}`);await run(page);assert.deepEqual(errors,[]);if(variant==='routed' && name==='ancestor-teardown'){const trace=await page.evaluate(()=>window.routingObserved.trace);assert.equal(trace.at(-1)?.kind,'listener-removed');assert.equal(trace.filter(x=>x.kind==='register').length,trace.filter(x=>x.kind==='unregister').length);}}catch(e){r.status='fail';r.error=e.message;}
|
|
r.observed=await page.evaluate(()=>({active:document.activeElement?.id,dialogs:document.querySelectorAll('[role=dialog]').length,...window.routingObserved}));r.browserErrors=errors;results.push(r);await page.close();
|
|
await writeFile('/tmp/fep-routing-checkpoint.json',JSON.stringify({status:'incomplete',results},null,2)+'\n');
|
|
}}finally{await browser.close();}
|
|
}
|
|
}finally{await new Promise(resolve=>server.close(resolve));}
|
|
const files={};for(const name of ['routing.mjs','routing-fixture.jsx','routing-transform.mjs','package.json','package-lock.json'])files[name]=hash(await readFile(dir+name));
|
|
const summary=[];for(const engine of ['chromium','firefox'])for(const mode of ['development','production'])for(const variant of ['raw','routed']){const r=results.filter(x=>x.engine===engine&&x.mode===mode&&x.variant===variant);summary.push({engine,mode,variant,passed:r.filter(x=>x.status==='pass').length,total:r.length});}
|
|
const output=process.env.FEP_RESULT_PATH||'/tmp/fep-routing.json';await writeFile(output,JSON.stringify({date:new Date().toISOString(),node:process.version,files,sourceSha256:hash(source),transformedSha256:hash(routeEscape(source)),bundleHashes:Object.fromEntries([...bundles].map(([k,v])=>[k,hash(v)])),summary,results},null,2)+'\n');console.log(JSON.stringify({output,summary},null,2));
|