SOURCE / PINNED RELEASE
Made of little things.
Limb Race
- Release
- 6a8ae4fc626e…
- Author-recorded commit
- 008c01ee6454…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-c2869f12ad8
Archive hash verified: 7be8492d1f89b891…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import assert from 'node:assert/strict';
const require=createRequire(realpathSync(new URL('../node_modules/@napplet/conformance-cli/package.json',import.meta.url)));
const {chromium}=require('playwright');
assert.ok(process.argv[2], 'Pass the URL printed by soyli dev');
const browser=await chromium.launch({headless:true});
try {
const page=await browser.newPage({viewport:{width:900,height:600}}),errors=[];
page.on('pageerror',e=>errors.push(e.message));
await page.goto(process.argv[2]);await page.waitForTimeout(1800);
let frame=page.frames().find(f=>f.url()==='about:srcdoc');assert.ok(frame);
async function size(w,h){
await page.setViewportSize({width:w,height:h});
await page.locator('iframe').evaluate((el,{w,h})=>{el.style.cssText=`position:fixed;inset:0;width:${w}px;height:${h}px;min-height:0;border:0;z-index:9999`;},{w,h});
await page.waitForTimeout(100);assert.deepEqual(await frame.evaluate(()=>[innerWidth,innerHeight]),[w,h]);
}
async function select(id){await frame.locator('#track-picker').click();await frame.locator(`[data-track="${id}"]`).click();}
await size(900,600);await select('sawtooth');
assert.equal(await frame.locator('#track-number').innerText(),'05 / 10');
await frame.locator('#clear').click();
const box=await frame.locator('#draw-canvas').boundingBox(),x=box.x+box.width/2,y=box.y+box.height/2,r=box.width*.43+1;
for(const [dx,dy]of [[1,1],[-1,1],[-1,-1],[1,-1]]){
await page.mouse.move(x,y);await page.mouse.down();await page.mouse.move(x+dx*r,y+dy*r);await page.mouse.up();
}
await frame.locator('#race').click();
await frame.locator('#message-title').filter({hasText:'Look at you go.'}).waitFor({timeout:45000});
console.log('CHALLENGE FINISH',await frame.locator('#message-detail').innerText());
assert.equal(await frame.locator('#share-result').isVisible(),false);
assert.equal(await frame.locator('.score-row').count(),1);
await frame.locator('#message-action').click();await frame.locator('#shared').click();
assert.match(await frame.locator('#score-list').innerText(),/personal challenge/i);
await frame.locator('#refresh').click();assert.match(await frame.locator('#score-status').innerText(),/Personal records only/);
await frame.locator('#personal').click();await frame.locator('.score-row').click();
assert.match(await frame.locator('#design-detail').innerText(),/Sawtooth/);await frame.locator('#use-design').click();
await select('pinpoint');assert.equal(await frame.locator('.score-row').count(),0);
await page.reload();await page.waitForTimeout(1500);frame=page.frames().find(f=>f.url()==='about:srcdoc');await size(900,600);
await select('sawtooth');assert.equal(await frame.locator('.score-row').count(),1);
for(const scheme of ['light','dark']){
await page.evaluate(scheme=>document.querySelector('iframe').contentWindow.postMessage({type:'theme.changed',theme:{colors:scheme==='dark'?{background:'#172521',text:'#e5ecdf',primary:'#a8cf8b'}:{background:'#f8f6ed',text:'#292d23',primary:'#72ac98'}}},'*'),scheme);
for(const [w,h]of [[200,160],[320,560],[900,600],[2400,1200]]){
await size(w,h);assert.equal(await frame.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false);
assert.equal(await frame.evaluate(()=>document.documentElement.classList.contains('dark')),scheme==='dark');
if(w===200){assert.equal(await frame.locator('.too-small').isVisible(),true);continue;}
await frame.locator('#track-picker').click();assert.equal(await frame.locator('.track-option').count(),10);
const dialog=await frame.locator('#tracks-dialog').boundingBox();assert.ok(dialog.y>=0&&dialog.y+dialog.height<=h);
assert.equal(await frame.locator('#tracks-dialog').evaluate(el=>el.scrollWidth>el.clientWidth),false);
if(h<=600)assert.equal(await frame.locator('#track-options').evaluate(el=>el.scrollHeight>el.clientHeight),true);
await frame.locator('[data-track="gauntlet"]').scrollIntoViewIfNeeded();
const close=await frame.locator('[data-close="tracks-dialog"]').boundingBox();assert.ok(close.y>=0&&close.y+close.height<=h);
assert.equal(await frame.locator('[data-track="gauntlet"] .difficulty').isVisible(),true);
assert.equal(await frame.locator('.track-option').evaluateAll(items=>items.every(item=>{const parent=item.getBoundingClientRect(),badge=item.querySelector('.difficulty').getBoundingClientRect();return badge.top>=parent.top&&badge.bottom<=parent.bottom;})),true,'difficulty badges stay inside their course rows');
await frame.locator('[data-track="gauntlet"]').click();assert.equal(await frame.locator('#track-number').innerText(),'10 / 10');
assert.equal(await frame.locator('#difficulty').innerText(),'EXTREME');
console.log('COURSE PICKER',scheme,w,h,'OK');
}
}
assert.deepEqual(errors,[]);
console.log('PASS: ten courses, real challenge finish, personal-only records, persistence, last-course selection and themed scrollable menus.');
} finally {await browser.close();}
