import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { SECURITY_HEADERS, esc, evidenceHtml, heroCardHtml, injectApp, invoiceHtml, landingHtml, pageFor } from '../worker/src/pages.js'; import { MAINNET } from '../evidence/mainnet.js'; const index = readFileSync(new URL('../web/index.html', import.meta.url), 'utf8'); /** Roughly what a fetcher that ignores JavaScript reads: tags and scripts dropped. */ const visible = (html) => html.replace(/<(script|style|template|svg)\b[\s\S]*?<\/\1>/gi, ' ').replace(/<[^>]+>/g, ' ').replace(/&[a-z#0-9]+;/gi, ' ').replace(/\s+/g, ' ').trim(); const paidInvoice = { id: '1-3', number: 3, merchant: 'a'.repeat(64), amount: '1000000', due_now: '0', paid: '1000000', applied: '1000000', excess: '0', set_aside: '200000', refunded: '0', status: 'paid', issued_at_ms: '1793542081622', due_at_ms: '1794787199000', closed_at_ms: '1793542204756', payments: [{ amount: '1000000', at_ms: '1793542204756', block: '222579868', refund_to: 'base:USDC:0xA30bDf2ea82D86a5feF686999B0b6c3d80c788cD' }], }; test('the landing reads without JavaScript: what Duly is, the contract, every transaction', () => { const page = injectApp(index, landingHtml(), { title: 'Duly' }); const text = visible(page); assert.ok(text.length > 2000, `only ${text.length} visible characters`); assert.doesNotMatch(text, /\bloading\b/i); assert.match(text, /dulypay\.near/); assert.ok(text.includes(MAINNET.codeHash)); for (const t of [...MAINNET.near, ...MAINNET.base]) assert.ok(page.includes(t.hash), `missing ${t.key}`); assert.match(page, /href="\/test\/app"/); assert.match(page, /href="\/i\/1-4"/); }); test('live totals appear only when the chain answered, and are escaped', () => { assert.doesNotMatch(landingHtml(), /live-totals/); const html = landingHtml({ live: { at: 1793542204756, invoices: '3', received: '1250000', liabilities: '1100000', held: '1100000' } }); assert.match(html, /1\.25 USDC received/); assert.ok(html.includes('<b>3</b>')); }); test('the test-mode landing says so', () => { assert.match(landingHtml({ test: true }), /Test mode\. No real money\./); }); test('injectApp fills the app root, keeps the scripts and replaces the noscript notice', () => { const page = injectApp(index, '

hello

', { title: 'A ', description: 'd"q' }); assert.match(page, /<div id="app"><p>hello<\/p><\/div>/); assert.match(page, /<script type="module" src="\/app\.js"><\/script>/); assert.match(page, /<title>A <title><\/title>/); assert.match(page, /content="d"q"/); assert.equal((page.match(/<noscript>/g) || []).length, 1); assert.match(page, /Everything above is readable without it/); assert.throws(() => injectApp('<html></html>', 'x'), /no app root/); }); test('a paid invoice shows its status, amounts and settlement links', () => { const html = invoiceHtml({ id: '1-3', inv: paidInvoice, verified: true, payments: [{ near_tx: 'GceCNYM3VvWnnN4x6ha7T9aU2j9PmzHyJnP6oc6pkreF', origin_tx: '0x0429a3f18c6b1a8681afb92ab58fb595e82672d9f5ecd94af57204370c63fa9a' }], }); const text = visible(html); assert.match(text, /PAID/); assert.match(text, /1\.00 USDC/); assert.match(text, /Set aside at settlement .* 0\.20/); assert.ok(html.includes('https://nearblocks.io/txns/GceCNYM3VvWnnN4x6ha7T9aU2j9PmzHyJnP6oc6pkreF')); assert.ok(html.includes('https://basescan.org/tx/0x0429a3f18c6b1a8681afb92ab58fb595e82672d9f5ecd94af57204370c63fa9a')); assert.doesNotMatch(html, /Pay this invoice/); }); test('the open sample invoice tells a reader how to pay it and which routes quoted', () => { const open = { ...paidInvoice, id: '1-4', number: 4, amount: '100000', due_now: '100000', paid: '0', set_aside: '0', status: 'open', payments: [] }; const html = invoiceHtml({ id: '1-4', inv: open, verified: true }); assert.match(html, /Pay this invoice/); assert.match(html, /public sample invoice/); assert.match(html, /Arbitrum/); // 1-2 was the first sample and falls due on 2026-11-15; it no longer calls itself the sample. const old = invoiceHtml({ id: '1-2', inv: { ...open, id: '1-2', number: 2 }, verified: true }); assert.match(old, /Pay this invoice/); assert.doesNotMatch(old, /public sample invoice/); }); test('chain data is escaped and only well-formed transaction hashes become links', () => { const evil = { ...paidInvoice, status: '<img src=x onerror=alert(1)>', payments: [{ amount: '1', at_ms: '1', block: '<b>', refund_to: 'base:<script>alert(1)</script>' }] }; const html = invoiceHtml({ id: '1-3', inv: evil, payments: [{ near_tx: 'javascript:alert(1)', origin_tx: '"><script>' }] }); assert.doesNotMatch(html, /<script>|<img src=x|javascript:/); assert.ok(html.includes('<script>')); }); test('a missing invoice and a silent chain are told apart', () => { assert.match(invoiceHtml({ id: '9-9', inv: null }), /No invoice with this number exists/); assert.match(invoiceHtml({ id: '9-9', inv: undefined }), /did not answer just now/); assert.doesNotMatch(visible(invoiceHtml({ id: '9-9', inv: undefined })), /\bloading\b/i); }); test('only the landing and invoice paths are server-rendered', () => { assert.deepEqual(pageFor('/'), { kind: 'landing', test: false }); assert.deepEqual(pageFor('/test'), { kind: 'landing', test: true }); assert.deepEqual(pageFor('/test/'), { kind: 'landing', test: true }); assert.deepEqual(pageFor('/i/1-3'), { kind: 'invoice', test: false, id: '1-3' }); assert.deepEqual(pageFor('/test/i/10-1'), { kind: 'invoice', test: true, id: '10-1' }); for (const p of ['/app', '/test/app', '/i/1-3/x', '/i/abc', '/i/1-3%3Cscript%3E', '/style.css', '/testing']) assert.equal(pageFor(p), null, p); }); test('server-rendered pages carry the same security headers as static files', () => { const file = readFileSync(new URL('../web/_headers', import.meta.url), 'utf8'); for (const [name, value] of Object.entries(SECURITY_HEADERS)) { const line = file.split('\n').find((l) => l.trim().toLowerCase().startsWith(`${name}:`)); assert.ok(line, `${name} missing from _headers`); assert.equal(line.trim().slice(name.length + 1).trim(), value, name); } }); test('esc covers the five HTML metacharacters', () => { assert.equal(esc(`<a href="x" title='y'>&</a>`), '<a href="x" title='y'>&</a>'); }); test('the prose evidence and the README carry every hash in the evidence data', () => { const md = readFileSync(new URL('../evidence/mainnet.md', import.meta.url), 'utf8'); for (const t of [...MAINNET.near, ...MAINNET.base]) assert.ok(md.includes(t.hash), `evidence/mainnet.md is missing ${t.key}`); const readme = readFileSync(new URL('../README.md', import.meta.url), 'utf8'); assert.ok(readme.includes(MAINNET.codeHash), 'README is missing the code hash'); for (const key of ['settle3', 'withdraw', 'refund']) assert.ok(readme.includes(MAINNET.near.find((t) => t.key === key).hash), `README is missing ${key}`); for (const key of ['pay3', 'payout', 'refundOut']) assert.ok(readme.includes(MAINNET.base.find((t) => t.key === key).hash), `README is missing ${key}`); }); test('the hero invoice is complete as served: invoice 1-3 Paid, the split from the evidence data, no "Due" text', () => { const html = heroCardHtml(); assert.ok(landingHtml().includes(html), 'the landing carries the hero invoice'); const start = html.indexOf('id="proof-inv"'); const end = html.indexOf('split in the same receipt', start); assert.ok(start > 0 && end > start, 'receipt block missing'); const text = visible(html.slice(start - 25, end + 40)); assert.match(text, /Invoice 1-3/); assert.match(text, /Paid/); assert.doesNotMatch(text, /\bDue\b/); const i3 = MAINNET.invoices.find((i) => i.id === '1-3'); assert.equal(i3.paid, '1000000'); assert.match(text, /Merchant 0\.80 USDC/); assert.match(text, /Tax set-aside 0\.20 USDC/); }); test('every evidence hash is a receipt row with an explorer link and a copy button', () => { const html = evidenceHtml(); for (const t of MAINNET.near) { assert.ok(html.includes(`href="https://nearblocks.io/txns/${t.hash}"`), `no explorer link for ${t.key}`); assert.ok(html.includes(`data-copy="${t.hash}"`), `no copy button for ${t.key}`); } for (const t of MAINNET.base) { assert.ok(html.includes(`href="https://basescan.org/tx/${t.hash}"`), `no explorer link for ${t.key}`); assert.ok(html.includes(`href="https://base.blockscout.com/tx/${t.hash}"`), `no Blockscout link for ${t.key}`); assert.ok(html.includes(`data-copy="${t.hash}"`), `no copy button for ${t.key}`); } assert.ok(html.includes(`data-copy="${MAINNET.codeHash}"`)); assert.match(visible(html), new RegExp(`re-checks all ${MAINNET.near.length + MAINNET.base.length} transactions`, 'i')); });