// 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);