aboutsummaryrefslogtreecommitdiffstats
path: root/tools/onboard-migrate-door-test.js
blob: 3b16dd0f205fbdc4b8df978e920804f6dc7c225f (plain) (blame)
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
65
66
67
68
69
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);