diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/onboard-migrate-door-test.js | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/tools/onboard-migrate-door-test.js b/tools/onboard-migrate-door-test.js new file mode 100644 index 0000000..3b16dd0 --- /dev/null +++ b/tools/onboard-migrate-door-test.js @@ -0,0 +1,70 @@ +// The front door's "Migrate a coinos account" button: people moving from +// the original coinos.io couldn't find the move, which waited behind the +// Spending offer. The door stashes the /migrate link's intent, explains that +// a wallet comes first, survives a refresh, and Back forgets the intent. +// +// Run: bun tools/onboard-migrate-door-test.js +import puppeteer from './puppeteer.js'; +import { buildHtml } from '../build.js'; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +let ok = true; +const check = (n, c, d = '') => { console.log(` ${c ? '✓' : '✗'} ${n}${d ? ' — ' + d : ''}`); if (!c) ok = false; }; + +const html = await buildHtml({ minify: true, pwa: false }); +const server = Bun.serve({ port: 5293, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) }); +const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] }); +const text = (page) => page.evaluate(() => document.body.innerText); +const waitText = async (page, x, ms = 20000) => { + for (let i = 0; i < ms / 250; i++) { if ((await text(page)).toLowerCase().includes(x.toLowerCase())) return true; await sleep(250); } + return false; +}; +const visible = (page) => page.evaluate(() => [...document.querySelectorAll('button')].filter((b) => b.offsetParent).map((b) => ({ id: b.id, text: b.textContent.trim() }))); +const clickText = (page, x) => page.evaluate((s) => { + const e = [...document.querySelectorAll('button')].find((n) => n.textContent.trim().toLowerCase().replace(/^[^a-z]+/, '') === s); + if (e) { e.click(); return true; } return false; +}, x.toLowerCase()); + +try { + const page = await browser.newPage(); + await page.setViewport({ width: 390, height: 844 }); + await page.goto('http://localhost:5293/', { waitUntil: 'domcontentloaded' }); + check('the front door paints', await waitText(page, 'create a new wallet')); + const btns = await visible(page); + const iMigrate = btns.findIndex((b) => b.id === 'onb-migrate'); + const iLastSignin = btns.map((b) => /sign in/i.test(b.text)).lastIndexOf(true); + check('a Migrate a coinos account button sits below the sign-in buttons', iMigrate > 0 && iMigrate > iLastSignin, + btns.map((b) => b.text).join(' | ')); + await page.click('#onb-migrate'); + check('it opens the move page', await waitText(page, 'move your coinos.io account', 5000)); + check('…which says a wallet and its words come first', /first, set up the wallet.*twelve words/i.test((await text(page)).replace(/\s+/g, ' '))); + const stashed = await page.evaluate(() => Number(localStorage.getItem('btc-wallet-migrate-link')) > 0); + check('the migrate intent is stashed, as the /migrate link stashes it', stashed); + const doors = await visible(page); + check('it offers Create plus the sign-in doors', doors.some((b) => b.id === 'onb-migrate-create') && doors.some((b) => /sign in with nostr/i.test(b.text)), + doors.map((b) => b.text).join(' | ')); + await page.reload({ waitUntil: 'domcontentloaded' }); + check('a refresh stays on the move page', await waitText(page, 'move your coinos.io account', 8000)); + check('Back returns to the front door', await clickText(page, 'back') && await waitText(page, 'create a new wallet', 5000)); + const forgot = await page.evaluate(() => !localStorage.getItem('btc-wallet-migrate-link')); + check('…and forgets the intent', forgot); + await page.click('#onb-migrate'); + await waitText(page, 'move your coinos.io account', 5000); + await page.click('#onb-migrate-create'); + check('Create my new wallet shows the twelve words', await waitText(page, 'set up your wallet', 5000)); + check('the intent survives into wallet creation', await page.evaluate(() => Number(localStorage.getItem('btc-wallet-migrate-link')) > 0)); + // the /migrate link on a device with no wallet: straight to the move page + const fresh = await browser.createBrowserContext(); + const linked = await fresh.newPage(); + await linked.setViewport({ width: 390, height: 844 }); + const pageErrors = []; + linked.on('pageerror', (e) => pageErrors.push(e.message)); + await linked.goto('http://localhost:5293/migrate', { waitUntil: 'domcontentloaded' }); + check('/migrate with no wallet opens on the move page', await waitText(linked, 'move your coinos.io account', 10000)); + check('…at the address bar root', await linked.evaluate(() => location.pathname === '/')); + check('no page errors', pageErrors.length === 0, pageErrors.join('; ')); +} finally { + await browser.close(); + server.stop(true); +} +console.log(ok ? '\n✅ the migrate door' : '\n❌ failures above'); +process.exit(ok ? 0 : 1); |
