aboutsummaryrefslogtreecommitdiffstats
path: root/tools/amount-field-unit-test.js
blob: 596969d083c63af902c5491162b64184ce26e0a0 (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
// Max (and fixed-amount invoices) fill the amount field in the unit it is
// showing: in fiat that is money to the cent, floored so a filled-in maximum
// never parses back to more sats than were offered — not a BTC figure under a
// CAD label (2026-10-08: Max on an ark recipient filled 0.00004978 'CAD').
// Switching the unit with an amount already typed into the send form converts
// it (2026-10-23): the same money in the new unit, round-tripping exactly.
// Run: bun tools/amount-field-unit-test.js
import assert from 'node:assert/strict';
import puppeteer from './puppeteer.js';

const bundle = await Bun.build({ entrypoints: ['src/app.js'], target: 'browser', minify: true,
  plugins: [{ name: 'amount-field-test', setup(build) {
    build.onLoad({ filter: /src\/app\.js$/ }, async ({ path }) => ({ loader: 'js', contents: await Bun.file(path).text() + `
window.amtApp = { ctx, ui, toggleUnit, get unit() { return unit; } };
` }));
    build.onLoad({ filter: /src\/video-compress\.js$/ }, () => ({ loader: 'js', contents: 'export async function compressVideo(f) { return f; }' }));
  } }] });
assert(bundle.success, bundle.logs.join('\n'));
const html = `<!doctype html><meta charset="utf-8"><div id="app"></div><script type="module">${await bundle.outputs[0].text()}</script>`;
const server = Bun.serve({ port: 0, fetch: (req) => new URL(req.url).pathname === '/'
  ? new Response(html, { headers: { 'Content-Type': 'text/html' } }) : new Response(null, { status: 404 }) });
const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: true, args: ['--no-sandbox'] });
try {
  const page = await browser.newPage(), errors = [];
  page.on('pageerror', (e) => errors.push(e.message));
  await page.setRequestInterception(true);
  page.on('request', (r) => r.url().startsWith(server.url.origin) ? r.continue() : r.abort());
  await page.evaluateOnNewDocument(() => {
    localStorage.setItem('btc-wallet-network', 'regtest');
    localStorage.setItem('btc-wallet-unit', 'fiat');
    localStorage.setItem('btc-wallet-currency', 'CAD');
    localStorage.setItem('btc-wallet-rates', JSON.stringify({ CAD: 150000, USD: 110000 }));
  });
  await page.goto(server.url.href, { waitUntil: 'domcontentloaded' });
  await page.waitForFunction(() => window.amtApp);
  const r = await page.evaluate(() => {
    const { ctx } = amtApp;
    const out = { unit: amtApp.unit, fiat: ctx.amountField(62212), back: ctx.parseAmount(ctx.amountField(62212), 'fiat'), typed: ctx.parseAmount('93.310', 'fiat') };
    while (amtApp.unit !== 'sats') amtApp.toggleUnit();
    out.sats = ctx.amountField(62212);
    amtApp.toggleUnit(); out.btc = ctx.amountField(62212);
    // typed into the send form, then the unit toggled around the ring
    while (amtApp.unit !== 'sats') amtApp.toggleUnit();
    const rs = amtApp.ui.send.recipients;
    rs[0].amount = '62212'; rs.push({ address: '', amount: '93.318' }, { address: '', amount: '' }, { address: '', amount: 'abc' });
    out.ring = [];
    for (let i = 0; i < 3; i++) { amtApp.toggleUnit(); out.ring.push([amtApp.unit, ...rs.map((r) => r.amount)]); }
    rs.splice(1);
    return out;
  });
  console.log(r);
  assert.equal(r.unit, 'fiat');
  assert.equal(r.fiat, '93.31', '62,212 sats at 150,000 CAD/BTC = 93.318 → floored to 93.31');
  assert.equal(r.back, 62212, 'the filled figure parses back to the exact sats — none left behind');
  assert.equal(r.typed, 62207, 'the same money typed as something else parses as typed');
  assert.equal(r.sats, '62212');
  assert.equal(r.btc, '0.00062212');
  assert.deepEqual(r.ring, [
    ['btc', '0.00062212', '0.00000093', '', 'abc'],
    ['fiat', '93.31', '0.13', '', 'abc'],
    ['sats', '62212', '93', '', 'abc'],
  ], 'a typed amount follows the unit around the ring and comes back exact; blanks and junk are left alone');
  assert.deepEqual(errors, []);
  console.log('✅ amount fills follow the display unit');
} finally { await browser.close(); server.stop(true); }