SOURCE / PINNED RELEASE
Made of little things.
Black Site
- Release
- 666bc7c74ebd…
- Author-recorded commit
- 05e95af79676…
- License
- LICENSE
- Author’s source reference
- nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-d2225ddc391
Archive hash verified: 1544e072e245c4a8…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
// Exercise the built app in an opaque-origin frame with controlled host responses.
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { createRequire } from 'node:module';
const requireHarness = createRequire(import.meta.resolve('@napplet/conformance-cli/package.json'));
const { chromium } = requireHarness('playwright');
const html = readFileSync(new URL('../dist/index.html', import.meta.url), 'utf8');
const png = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aV1sAAAAASUVORK5CYII=';
const browser = await chromium.launch({ args: ['--no-sandbox'] });
try {
for (const mode of ['avatar', 'no-resource', 'denied', 'stale-avatar', 'no-identity']) {
const page = await browser.newPage({ viewport: { width: 900, height: 600 } });
const errors = [];
page.on('pageerror', error => errors.push(error.message));
const fixture = `<script>
const mode = ${JSON.stringify(mode)};
window.napplet = {};
window.fixtureClosed = false;
window.fixtureReads = 0;
window.fixtureRevoked = 0;
const revoke = URL.revokeObjectURL.bind(URL);
URL.revokeObjectURL = url => { window.fixtureRevoked++; revoke(url); };
if (mode !== 'no-identity') {
window.napplet.identity = {
getPublicKey: async () => 'a'.repeat(64),
onChanged: callback => { window.fixtureChange = callback; return { close: () => { window.fixtureClosed = true; } }; }
};
window.napplet.common = { getProfile: async key => ({ ok: true, pubkey: key, profile: {
display_name: key === 'a'.repeat(64) ? 'Alice Player' : 'Bob Player', picture: 'https://example.com/avatar.png'
} }) };
}
if (mode !== 'no-resource') window.napplet.resource = { bytes: async () => {
window.fixtureReads++;
if (mode === 'denied') throw new Error('blocked-by-policy');
if (mode === 'stale-avatar') await new Promise(resolve => { window.fixtureResolveAvatar = resolve; });
return new Blob([Uint8Array.from(atob(${JSON.stringify(png)}), c => c.charCodeAt(0))], { type: 'image/png' });
} };
</script>`;
await page.setContent('<iframe sandbox="allow-scripts" style="position:fixed;inset:0;border:0;width:100%;height:100%"></iframe>');
await page.locator('iframe').evaluate((iframe, source) => { iframe.srcdoc = source; }, html.replace('<head>', '<head>' + fixture));
const frame = await (await page.locator('iframe').elementHandle()).contentFrame();
await frame.locator('#menu.on').waitFor();
const label = mode === 'no-identity' ? 'Guest player' : 'Alice Player';
await frame.waitForFunction(text => document.querySelector('.player-label')?.textContent === text, label);
assert.equal(await frame.locator('#menu .hint').count(), 0);
assert.ok(await frame.locator('#currentUser').evaluate(el => el.getBoundingClientRect().width) >= 420);
assert.doesNotMatch(await frame.locator('#currentUser').innerText(), /nostr|refresh/i);
if (mode === 'avatar') {
await frame.locator('#currentUser img').waitFor({ state: 'attached' });
assert.equal(await frame.locator('#currentUser img').evaluate(img => img.complete && img.naturalWidth > 0), true);
assert.match(await frame.locator('#currentUser img').getAttribute('src'), /^blob:/);
assert.equal(await frame.evaluate(() => window.fixtureReads), 1);
} else {
assert.equal(await frame.locator('#currentUser img').count(), 0);
}
await frame.locator('#currentUser').click();
await frame.locator('#playerAccount.on').waitFor();
assert.doesNotMatch(await frame.locator('#playerAccount').innerText(), /nostr|pubkey|refresh|host/i);
await frame.waitForFunction(() => document.querySelector('#playerAccount .sync-warning'));
assert.match(await frame.locator('#playerAccount .sync-warning:visible').innerText(), /runtime.*features needed for sync/);
assert.equal(await frame.locator('#playerAccount .armory-sync button:visible').count(), 0, 'unsupported runtimes show no sync actions');
await page.keyboard.press('Escape');
await frame.locator('#menu.on').waitFor();
await frame.locator('#helpButton').click();
await frame.locator('#howToPlay.on').waitFor();
assert.match(await frame.locator('#howToPlay').innerText(), /LEFT CLICK/);
await frame.locator('#howToPlay [data-go=menu]').click();
if (mode !== 'no-identity') {
await frame.evaluate(() => window.fixtureChange(''));
if (mode === 'stale-avatar') await frame.evaluate(() => window.fixtureResolveAvatar());
await frame.waitForFunction(() => document.querySelector('.player-label').textContent === 'Guest player');
assert.equal(await frame.locator('#currentUser img').count(), 0);
if (mode === 'avatar') assert.equal(await frame.evaluate(() => window.fixtureRevoked), 1);
await frame.evaluate(() => window.dispatchEvent(new Event('pagehide')));
assert.equal(await frame.evaluate(() => window.fixtureClosed), true);
}
assert.deepEqual(errors, []);
console.log(`PASS player UI: ${mode}`);
await page.close();
}
} finally { await browser.close(); }
