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 {openAnatomy,closeAnatomy} from './anatomy-ui-helpers.mjs';
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import {mkdir,readFile} from 'node:fs/promises';
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});
const output='.napplet-space/visibility-checks';await mkdir(output,{recursive:true});
const errors=[];
const resize=async(page,iframe,w,h)=>{await page.setViewportSize({width:w,height:h});await iframe.evaluate((e,[w,h])=>e.style.cssText=`position:fixed;inset:0;width:${w}px;height:${h}px;z-index:9999;border:0;min-width:0;min-height:0`,[w,h]);await page.evaluate(()=>new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))));};
try{
const page=await browser.newPage({viewport:{width:1600,height:1000}});page.on('pageerror',e=>errors.push(e.message));await page.goto(process.argv[2]);
const iframe=page.locator('iframe');await iframe.waitFor();const f=await(await iframe.elementHandle()).contentFrame();await f.locator('#app[data-ready="true"]').waitFor();
for(const theme of ['light','dark']){
await page.setViewportSize({width:1600,height:1000});await iframe.evaluate(e=>e.style.cssText='');
const appearance=page.getByRole('button',{name:/Appearance:/});let label='';
for(let i=0;i<4;i++){label=(await appearance.getAttribute('aria-label'))||await appearance.innerText();if(label.toLowerCase().includes(theme))break;await appearance.click();}
assert.ok(label.toLowerCase().includes(theme));
for(const [w,h] of [[1600,1000],[900,600],[320,560],[200,160]]){
await resize(page,iframe,w,h);assert.deepEqual(await f.evaluate(()=>[innerWidth,innerHeight]),[w,h]);
if(w===200){assert.ok(await f.locator('.minimum-notice').isVisible());await page.screenshot({path:`${output}/${theme}-${w}.png`});continue;}
if(w<761)await f.locator('button[data-panel="body"]').click();
await openAnatomy(f);await f.locator('#anatomySearch').fill('');const expand=f.locator('[data-expand="region:left-arm"]');await expand.focus();await expand.press('Space');assert.equal(await f.evaluate(()=>document.activeElement.dataset.expand),'region:left-arm');await f.locator('#anatomySearch').fill('left hand');
const hand=f.locator('[data-visibility="region:left-hand"]');await hand.focus();await hand.press('Space');
assert.equal(await f.locator('#bodyViewport').getAttribute('data-focus'),'whole');
const palette=await f.locator('#anatomyPanel').evaluate(e=>({background:getComputedStyle(e).backgroundColor,ink:getComputedStyle(e).color,accent:getComputedStyle(document.documentElement).getPropertyValue('--emphasis').trim()}));
assert.deepEqual(palette,{background:'rgb(255, 255, 255)',ink:'rgb(32, 33, 36)',accent:'#c43c20'});
await page.screenshot({path:`${output}/${theme}-${w}.png`});await closeAnatomy(f);
}
}
const absent=await browser.newPage({viewport:{width:900,height:600}});absent.on('pageerror',e=>errors.push(e.message));await absent.setContent('<iframe sandbox="allow-scripts" style="position:fixed;inset:0;width:900px;height:600px;border:0"></iframe>');
const ai=absent.locator('iframe');await ai.evaluate((e,html)=>e.srcdoc=html,await readFile('dist/index.html','utf8'));const af=await(await ai.elementHandle()).contentFrame();await af.locator('#app[data-ready="true"]').waitFor();
await openAnatomy(af);await af.locator('#hideAllAnatomy').click();assert.equal(await af.locator('#bodyViewport').getAttribute('data-hidden'),'46');await closeAnatomy(af);
await openAnatomy(af);await af.locator('#anatomySearch').fill('left hand');await af.locator('button[data-focus="region:left-hand"]').click();await af.locator('#applyFocus').click();await closeAnatomy(af);
assert.equal(await af.locator('#bodyViewport').getAttribute('data-hidden'),'46');assert.match(await af.locator('#sessionStatus').innerText(),/session only/i);await absent.close();
const touch=await browser.newContext({viewport:{width:390,height:844},hasTouch:true,isMobile:true}),tp=await touch.newPage();tp.on('pageerror',e=>errors.push(e.message));await tp.goto(process.argv[2]);const ti=tp.locator('iframe');await ti.waitFor();const tf=await(await ti.elementHandle()).contentFrame();await tf.locator('#app[data-ready="true"]').waitFor();
for(const [w,h] of [[390,844],[844,390]]){
await resize(tp,ti,w,h);assert.deepEqual(await tf.evaluate(()=>[innerWidth,innerHeight]),[w,h]);
if(w<761)await tf.locator('button[data-panel="body"]').tap();
await openAnatomy(tf);await tf.locator('#hideAllAnatomy').tap();await tf.locator('#anatomySearch').fill('left hand');await tf.locator('[data-visibility="region:left-hand"]').tap();
assert.ok(await tf.locator('[data-visibility="region:left-index"]').isChecked());await tp.screenshot({path:`${output}/touch-${w}.png`});await closeAnatomy(tf);
const hidden=await tf.locator('#bodyViewport').getAttribute('data-hidden');await openAnatomy(tf);await tf.locator('#anatomySearch').fill('right hand');await tf.locator('button[data-focus="region:right-hand"]').tap();await tf.locator('#applyFocus').tap();await closeAnatomy(tf);
assert.equal(await tf.locator('#bodyViewport').getAttribute('data-hidden'),hidden);assert.equal(await tf.locator('#bodyViewport').getAttribute('data-focus'),'region:right-hand');
}
assert.deepEqual(errors,[]);console.log('PASS: hierarchical visibility with keyboard and touch, explicit focus preserves hidden anatomy, all four actual frames in both host themes, missing optional domains.');
}finally{await browser.close();}
