aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-07 13:25:49 -0700
committerAdam Soltys <[email protected]>2026-10-07 13:25:49 -0700
commit39ce1ef4c04bf010c75b3431be69174d6ef2c80a (patch)
tree36c97d8912e3c47633edc77e5f45cb39dfb2a264 /tools
parente3bc27dc7540fea6f8eaf5094627e28a089cf6b7 (diff)
downloadcoinosv3-39ce1ef4c04bf010c75b3431be69174d6ef2c80a.tar.gz
coinosv3-39ce1ef4c04bf010c75b3431be69174d6ef2c80a.zip
Setup wizard: a cover behind the avatar — twelve nature covers (self-hosted, Unsplash) cycled with arrows or a swipe, or upload your own; untouched, each pubkey gets its own default, published as the kind-0 banner beside the punk
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'tools')
-rw-r--r--tools/onboard-cover-test.js64
1 files changed, 64 insertions, 0 deletions
diff --git a/tools/onboard-cover-test.js b/tools/onboard-cover-test.js
new file mode 100644
index 0000000..4262bc1
--- /dev/null
+++ b/tools/onboard-cover-test.js
@@ -0,0 +1,64 @@
+// The wizard's "Choose your look" step: a cover sits behind the avatar,
+// defaulting to this pubkey's own, and its arrows (or a swipe) cycle the
+// twelve nature covers with a counter; the preview copies are what load.
+// Run: bun run build && bun tools/onboard-cover-test.js [screenshot.png]
+import assert from 'node:assert/strict';
+import puppeteer from './puppeteer.js';
+const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+const server = Bun.serve({ port: 0, async fetch(req) {
+ const p = new URL(req.url).pathname;
+ const f = Bun.file('dist' + (p === '/' ? '/index.html' : p));
+ return (await f.exists()) ? new Response(f) : new Response(Bun.file('dist/index.html'), { headers: { 'content-type': 'text/html' } });
+} });
+const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: true, args: ['--no-sandbox'] });
+try {
+ const page = await browser.newPage();
+ const errors = [];
+ page.on('pageerror', (e) => errors.push(String(e)));
+ await page.setViewport({ width: 390, height: 844, deviceScaleFactor: 2 });
+ await page.goto(server.url.href);
+ await page.evaluate(() => localStorage.setItem('btc-wallet-network', 'regtest'));
+ await page.reload(); await sleep(1200);
+ const click = (x) => page.evaluate((x) => { const e = [...document.querySelectorAll('button')].find((n) => n.textContent.trim().toLowerCase().includes(x)); e?.click(); return !!e; }, x);
+ await click('create a new wallet'); await sleep(1500);
+ await click('skip verification'); await sleep(1500);
+ await page.evaluate(() => localStorage.setItem('btc-wallet-onb-step', 'avatar'));
+ await page.reload();
+ await page.waitForSelector('.onb-cover', { timeout: 10000 });
+ const state = () => page.evaluate(() => {
+ const c = document.querySelector('.onb-cover');
+ return { count: document.querySelector('.onb-cover-count').textContent, bg: c.style.backgroundImage };
+ });
+ const first = await state();
+ assert.match(first.count, /^\d+ \/ 12$/, 'a default cover is chosen: ' + first.count);
+ assert.match(first.bg, /covers-sm\/\d+\.webp/);
+ const n = Number(first.count.split(' ')[0]);
+ await page.click('.onb-cover-nav.next'); await sleep(100);
+ assert.equal((await state()).count, `${n % 12 + 1} / 12`, 'next moves on, wrapping at twelve');
+ await page.click('.onb-cover-nav.prev'); await page.click('.onb-cover-nav.prev'); await sleep(100);
+ assert.equal((await state()).count, `${((n - 2 + 12) % 12) + 1} / 12`, 'previous goes back, wrapping');
+ // a swipe left is "next"
+ const box = await (await page.$('.onb-cover')).boundingBox();
+ const before = Number((await state()).count.split(' ')[0]);
+ // across the cover's open upper part (the avatar covers the lower middle)
+ const y = box.y + box.height * 0.3;
+ await page.mouse.move(box.x + box.width * 0.6, y);
+ await page.mouse.down(); await page.mouse.move(box.x + box.width * 0.3, y, { steps: 5 }); await page.mouse.up();
+ await sleep(100);
+ assert.equal((await state()).count, `${before % 12 + 1} / 12`, 'a swipe left shows the next cover');
+ // the cover image itself really loads, and the avatar sits over its bottom edge
+ const loaded = await page.evaluate(async () => {
+ const url = document.querySelector('.onb-cover').style.backgroundImage.match(/url\("?(.*?)"?\)/)[1];
+ const im = new Image(); im.src = url; await im.decode(); return im.naturalWidth;
+ });
+ assert.equal(loaded, 750);
+ const overlap = await page.evaluate(() => {
+ const c = document.querySelector('.onb-cover').getBoundingClientRect(), a = document.querySelector('.onb-avatar').getBoundingClientRect();
+ return a.top < c.bottom && a.bottom > c.bottom;
+ });
+ assert(overlap, 'the avatar overlaps the cover\'s bottom edge');
+ if (process.argv[2]) await page.screenshot({ path: process.argv[2] });
+ assert.deepEqual(errors, []);
+ console.log('✓ the look step: default cover, arrows and swipe cycle twelve covers, avatar over the cover');
+} finally { await browser.close(); server.stop(true); }
+process.exit(0);