aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/onboard-migrate-door-test.js70
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);