1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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);
|