Files

26 lines
3.9 KiB
JavaScript

import {chromium} from '@playwright/test';
import fs from 'node:fs';import path from 'node:path';import {pathToFileURL} from 'node:url';import assert from 'node:assert/strict';import crypto from 'node:crypto';
const root=path.resolve(import.meta.dirname,'..'),file=path.join(root,'dist/mechanism-demo-0.2.0.html');
const browser=await chromium.launch({headless:true,...(process.env.CHROMIUM_EXECUTABLE?{executablePath:process.env.CHROMIUM_EXECUTABLE}:{})});
const report={sha256:crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'),runs:[]};
fs.mkdirSync(path.join(root,'evidence'),{recursive:true});
try{for(const reducedMotion of ['no-preference','reduce']){
const ctx=await browser.newContext({offline:true,reducedMotion,viewport:{width:1280,height:900}}),p=await ctx.newPage(),errors=[],network=[];
p.on('pageerror',e=>errors.push(String(e)));p.on('console',m=>{if(m.type()==='error')errors.push(m.text());});p.on('request',r=>{if(/^https?:/.test(r.url()))network.push(r.url());});
await p.goto(pathToFileURL(file).href);await p.evaluate(()=>document.fonts.ready);
const state=()=>p.evaluate(()=>mechanismQA.state());const settled=()=>p.waitForFunction(()=>!mechanismQA.state().active);
assert.deepEqual((await state()).positions,[460,520,580]);
if(reducedMotion==='no-preference')await p.screenshot({path:path.join(root,'evidence/mechanism-assembled.png')});
await p.locator('#explode').click();if(reducedMotion==='no-preference'){await p.waitForTimeout(150);const s=await state();assert.ok(s.positions[0]<460&&s.positions[0]>200,'actual intermediate motion');}await settled();assert.deepEqual((await state()).positions,[200,520,840]);
const clipped=await p.evaluate(()=>{const r=document.querySelector('svg').getBoundingClientRect();return [...document.querySelectorAll('svg text')].filter(e=>{const b=e.getBoundingClientRect();return b.left<r.left||b.right>r.right||b.top<r.top||b.bottom>r.bottom;}).map(e=>e.textContent);});assert.deepEqual(clipped,[]);
if(reducedMotion==='no-preference')await p.screenshot({path:path.join(root,'evidence/mechanism-exploded.png')});
for(let i=0;i<3;i++){const n=p.locator(`[data-index="${i}"]`);for(const action of ['click','Enter','Space']){if(action==='click')await n.click();else{await n.focus();await p.keyboard.press(action);}await settled();assert.equal((await state()).selected,i);assert.equal(await n.getAttribute('aria-pressed'),'true');assert.equal(await p.locator('#detail-title').textContent(),['Interface','Processing','Storage'][i]);}}
if(reducedMotion==='no-preference')await p.screenshot({path:path.join(root,'evidence/mechanism-inspected.png')});
for(const id of ['reassemble','assemble']){await p.locator('#'+id).click();await settled();assert.deepEqual((await state()).positions,[460,520,580]);assert.equal((await state()).selected,-1);}
await p.locator('#inspect').focus();await p.keyboard.press('Enter');await settled();assert.equal((await state()).selected,1);
await p.evaluate(()=>{for(const id of ['assemble','explode','reassemble','explode','assemble'])document.getElementById(id).click();});await settled();assert.deepEqual((await state()).positions,[460,520,580]);
await p.locator('#explode').click();await p.emulateMedia({reducedMotion:'reduce'});await settled();assert.deepEqual((await state()).positions,[200,520,840]);
await p.locator('#assemble').click();await p.emulateMedia({media:'print'});await p.evaluate(()=>dispatchEvent(new Event('beforeprint')));assert.deepEqual((await state()).positions,[200,520,840]);assert.equal(await p.locator('.controls').isVisible(),false);
assert.deepEqual(errors,[]);assert.deepEqual(network,[]);report.runs.push({reducedMotion,components:3,componentActions:9,controls:4,interruption:true,print:true,clipped,errors,network});await ctx.close();
}fs.writeFileSync(path.join(root,'evidence/mechanism-test-report.json'),JSON.stringify(report,null,2)+'\n');console.log(JSON.stringify(report,null,2));}finally{await browser.close();}