SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import {execFileSync} from 'node:child_process';
const require=createRequire(realpathSync('node_modules/@napplet/conformance-cli/package.json'));
const {chromium}=require('playwright');
const info=JSON.parse(execFileSync('soyli',['browser','path','--json'],{encoding:'utf8'}));
const browser=await chromium.launch({executablePath:info.executables.find(e=>e.name==='chromium'&&e.installed).path,headless:true});
try {
const context=await browser.newContext({viewport:{width:1400,height:950},hasTouch:true});
const page=await context.newPage(),errors=[];page.on('pageerror',e=>errors.push(e.message));
await page.goto(process.argv[2]);const iframe=page.locator('iframe');await iframe.waitFor();
await iframe.evaluate(e=>e.style.cssText='position:fixed;inset:0;width:1400px;height:950px;z-index:9999;border:0');
const f=await(await iframe.elementHandle()).contentFrame();await f.locator('#app[data-ready="true"]').waitFor();
const canvas=f.locator('canvas'),box=await canvas.boundingBox(),x=box.x+box.width*.5,y=box.y+box.height*.4;
const cdp=await context.newCDPSession(page);
const touch=(type,points)=>cdp.send('Input.dispatchTouchEvent',{type,touchPoints:points.map(([id,x,y])=>({id,x,y,radiusX:3,radiusY:3}))});
// Clipped element screenshots can offset subsequent CDP touch coordinates in Chromium.
const shot=async()=>{await page.waitForTimeout(70);return (await page.screenshot()).toString('base64');};
for(const mode of ['rotate','paint','pose']) {
await f.locator(`button[data-mode="${mode}"]`).click();await f.locator('[data-view="front"]').click();
const before=await shot(),count=await f.locator('#concernCount').innerText();
await page.mouse.move(x,y);await page.mouse.down({button:'right'});await page.mouse.move(x+90,y+20,{steps:10});await page.mouse.up({button:'right'});
assert.ok((await shot())!==before,`${mode}: right drag rotates`);
assert.equal(await f.locator('#concernCount').innerText(),count,`${mode}: right drag creates no observation`);
assert.equal(await f.locator(`button[data-mode="${mode}"]`).getAttribute('aria-pressed'),'true');
await f.locator('[data-view="front"]').click();const first=await shot();
await touch('touchStart',[[1,x-40,y],[2,x+40,y]]);
await touch('touchMove',[[1,x+10,y+15],[2,x+90,y+15]]);
const rotated=await shot();assert.ok(rotated!==first,`${mode}: two fingers rotate`);
await touch('touchEnd',[[2,x+90,y+15]]);await touch('touchMove',[[1,x+50,y+45]]);
assert.ok((await shot())===rotated,`${mode}: remaining finger cannot edit or rotate`);
await touch('touchEnd',[]);
assert.equal(await f.locator('#concernCount').innerText(),count,`${mode}: no initial dot or final stray stroke`);
assert.equal(await f.locator(`button[data-mode="${mode}"]`).getAttribute('aria-pressed'),'true');
await page.mouse.move(x,y);const preScroll=await shot();await page.mouse.wheel(0,80);
assert.ok((await shot())!==preScroll,`${mode}: trackpad scroll zooms`);
}
// A fresh one-finger tap still paints after all override gestures have ended.
await f.locator('button[data-mode="paint"]').click();await f.locator('[data-view="front"]').click();
await touch('touchStart',[[1,x,y]]);await touch('touchEnd',[]);
assert.equal(await f.locator('#concernCount').innerText(),'1');
assert.deepEqual(errors,[]);
console.log('PASS: right drag, two-finger touch drag and trackpad scroll in Rotate/Mark/Pose; no stray marks; tool retained; one-finger paint resumes.');
} finally {await browser.close();}
