Back to Napcraft
SOURCE / PINNED RELEASE

Made of little things.

Napcraft

Release
ee47ac6a25df…
Author-recorded commit
410dea87e109…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-52f9e22f5ce

Archive hash verified: 9e6e0cabb18d0d46…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/directory-host.mjs
import {chromium,executable,frameOf,connectTestIdentity,installTestIdentity,approveLocalPrompts,fitFrame} from './browser-support.mjs';
import {startLocalRelay,useLocalRelay,browserArgs} from './local-relay.mjs';
import {writeFile} from 'node:fs/promises';
import assert from 'node:assert/strict';
const publicHost=process.env.NAPCRAFT_PUBLIC==='1';
const relay=publicHost?undefined:await startLocalRelay(), browser=await chromium.launch({executablePath:executable,headless:true,args:browserArgs});
const players=[],checks=[],name=`Garden gates ${Date.now().toString(36)}`;
async function getFrame(page){
  if(!publicHost)return frameOf(page);
  const frame=await(await page.locator('iframe[title="Napcraft"]').elementHandle()).contentFrame();await frame.locator('#app[data-ready=true]').waitFor();return frame;
}
async function openApp(page){await page.goto(process.env.NAPCRAFT_URL,{waitUntil:'domcontentloaded'});if(publicHost)await page.getByRole('button',{name:'Start Napcraft',exact:true}).click({timeout:45000});return getFrame(page)}
async function connect(p){
  if(!publicHost)await connectTestIdentity(p.page);
  else{await installTestIdentity(p.page);await p.page.getByRole('button',{name:'Connect',exact:true}).click();await p.page.getByRole('button',{name:'Connect browser extension',exact:true}).click();await p.page.getByRole('button',{name:'Connect',exact:true}).waitFor({state:'hidden'});p.frame=await getFrame(p.page)}
}
function approve(page){
  if(!publicHost)return approveLocalPrompts(page);
  let stopped=false;
  void(async()=>{while(!stopped&&!page.isClosed()){
    for(const [name,button] of [['Allow network connection','Connect'],['Allow multiplayer connections','Allow'],['Approve public action','Approve & publish']]){
      const dialog=page.getByRole('dialog',{name,exact:true});try{if(await dialog.isVisible())await dialog.getByRole('button',{name:button,exact:true}).click({timeout:1000})}catch{}
    }await new Promise(r=>setTimeout(r,100));
  }})();return()=>{stopped=true};
}
const check=(label,ok=true)=>{assert.ok(ok,label);checks.push(label);console.log('PASS',label)};
const refresh=async p=>{await p.frame.locator('.directory-refresh').click();await p.frame.locator('.directory-refresh').waitFor({state:'visible'});await p.frame.waitForFunction(()=>!document.querySelector('.directory-refresh')?.disabled)};
const saved=(p,n)=>p.frame.waitForFunction(n=>document.querySelector('canvas').dataset.confirmedEdits===String(n)&&document.querySelector('#app').dataset.pending==='0',n,{timeout:30000});
try {
  for(let i=0;i<2;i++){
    const context=await browser.newContext({viewport:{width:1200,height:900},hasTouch:i===1});if(relay)await useLocalRelay(context,relay.config);
    const page=await context.newPage(),frame=await openApp(page);players.push({page,frame,stop:approve(page)});
  }
  const [a,b]=players;
  await connect(a);await a.frame.locator('#create').click();await a.frame.locator('#name').fill(name);await a.frame.locator('#confirmCreate').click();await a.frame.locator('#share').waitFor({timeout:60000});
  await a.frame.waitForFunction(()=>!document.querySelector('#place').disabled);await a.frame.locator('#share').click();
  const code=await a.frame.locator('#shareCode').inputValue();await a.frame.getByRole('button',{name:'List publicly',exact:true}).waitFor();
  await refresh(b);check('unlisted world does not appear in public directory',await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).count()===0);
  a.stop();await a.page.waitForTimeout(200);
  await a.frame.locator('#listWorld').click();
  const prompt=publicHost?a.page.getByRole('dialog',{name:'Approve public action',exact:true}):a.page.locator('#prompt[open]');await prompt.waitFor();
  await prompt.getByRole('button',{name:'Cancel',exact:true}).click();
  await a.frame.getByRole('button',{name:'Retry listing',exact:true}).waitFor();
  check('denied listing keeps world code and offers retry',(await a.frame.locator('#shareCode').inputValue())===code);
  a.stop=approve(a.page);
  await a.frame.evaluate(()=>{
    const original=window.napplet.outbox.publish.bind(window.napplet.outbox);window.listingCalls=[];let lose=true;
    window.napplet.outbox.publish=async(template,options)=>{window.listingCalls.push(JSON.stringify(template));const r=await original(template,options);if(r.ok&&lose){lose=false;throw Error('Test lost listing acknowledgement')}return r};
  });
  await a.frame.locator('#listWorld').click();await a.frame.locator('.listing-status').filter({hasText:'Test lost listing acknowledgement'}).waitFor();
  await a.frame.locator('#listWorld').click();await a.frame.getByRole('button',{name:'Remove my listing',exact:true}).waitFor();
  check('lost publication reply retries the identical event template',await a.frame.evaluate(()=>window.listingCalls.length===2&&window.listingCalls[0]===window.listingCalls[1]));
  await refresh(b);await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).waitFor();
  check('anonymous independent browser discovers listed world without a code');
  await b.frame.locator('#worldSearch').fill('no-such-garden');check('search filters the loaded worlds',await b.frame.locator('.world-row').count()===0);await b.frame.locator('#worldSearch').fill('');
  if(publicHost){await b.page.setViewportSize({width:390,height:844});await b.page.getByText('Open player',{exact:true}).click();b.frame=await getFrame(b.page)}else await fitFrame(b.page,390,844);
  await b.page.locator(publicHost?'iframe[title="Napcraft"]':'#stage iframe').screenshot({path:'.napplet-space/promotion/directory-phone.png'});
  await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).tap();await b.frame.locator('#share').waitFor();await b.frame.waitForFunction(()=>!document.querySelector('#place').disabled);
  await a.frame.locator('#close').click();await b.frame.locator('#place').tap();await Promise.all(players.map(p=>saved(p,1)));
  check('phone touch joins listed world and edits are shared');
  await Promise.all(players.map(async p=>{p.frame=await openApp(p.page);if(publicHost&&p===b){await p.page.getByText('Open player',{exact:true}).click();p.frame=await getFrame(p.page)}}));
  await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).waitFor();check('listing survives both players leaving and reloading');
  await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).click();await saved(b,1);check('directory join restores the persistent edited world');
  if(publicHost){await b.page.setViewportSize({width:1200,height:900});b.frame=await openApp(b.page)}
  await connect(b);await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).waitFor();await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).click();await b.frame.locator('#share').click();
  await b.frame.getByRole('button',{name:'List publicly',exact:true}).waitFor();check('second identity cannot remove another player listing');
  if(!publicHost&&(await a.page.locator('#connect').innerText())!=='Disconnect')await a.page.locator('#connect').click();
  await a.frame.getByRole('button',{name:`Join ${name}`,exact:true}).waitFor();
  await a.page.locator(publicHost?'iframe[title="Napcraft"]':'#stage iframe').screenshot({path:'.napplet-space/promotion/directory-desktop.png'});
  await a.frame.getByRole('button',{name:`Join ${name}`,exact:true}).click();await a.frame.locator('#share').click();await a.frame.getByRole('button',{name:'Remove my listing',exact:true}).click();await a.frame.getByRole('button',{name:'List publicly',exact:true}).waitFor();
  await b.frame.locator('#close').click();await b.frame.locator('#worldMenu').click();await refresh(b);
  check('unlisted world disappears for another identity',await b.frame.getByRole('button',{name:`Join ${name}`,exact:true}).count()===0);
  await b.frame.locator('#join').click();await b.frame.locator('#code').fill(code);await b.frame.locator('#confirmJoin').click();await saved(b,1);check('unlisting preserves world and direct-code access');
  await b.frame.evaluate(()=>{window.napplet.outbox.query=async()=>{throw Error('Test directory connection unavailable')}});await b.frame.locator('#worldMenu').click();
  await b.frame.locator('.directory-status').filter({hasText:'Test directory connection unavailable'}).waitFor();await b.frame.locator('#practice').click();check('directory outage still permits practice');
  await writeFile('.napplet-space/directory-host-results.json',JSON.stringify({passed:true,checks,name,code,publicHost},null,2));
}catch(error){for(const p of players)console.log('DIRECTORY FAILURE',await p.frame.locator('#panel').innerText().catch(()=>''),(await p.page.locator('body').innerText()).slice(-1600));throw error;}
finally{players.forEach(p=>p.stop());await browser.close();await relay?.close();}