import { test } from 'node:test'; import assert from 'node:assert/strict'; import { isEmail, mailLayout, esc } from '../src/lib/mail.ts'; test('Valid addresses are recognised', () => { for (const good of ['first.last@example.com', 'a.b+c@sub.example.co.uk', 'x@y.de', 'Gran_1949@example.de']) { assert.ok(isEmail(good), `wrongly rejected: ${good}`); } }); test('Invalid addresses are rejected — including the ones with a line break appended', () => { const bad = [ '', ' ', 'not-an-address', 'a@b', '@b.de', 'a@.de', 'a b@c.de', 'a@b .de', 'a@b.de\nBcc: victim@example.com', // header injection 'a@b.de\r\nSubject: x', 'a@b.de\n', // JavaScript's "$" also matches before a line end 'a'.repeat(250) + '@b.de', // too long ]; for (const s of bad) assert.ok(!isEmail(s), `slipped through: ${JSON.stringify(s)}`); }); test('esc defuses everything that could take the HTML apart', () => { assert.equal(esc('x'), '<b>x</b>'); assert.equal(esc('a & b'), 'a & b'); assert.equal(esc('said "hello"'), 'said "hello"'); // Order: & first, otherwise < would become &lt; assert.equal(esc('<&>'), '<&>'); }); test('The heading of the mail is always escaped', () => { const html = mailLayout('', ['Text']); assert.ok(!html.includes('' }); assert.ok(!html.includes('