import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { extractEmail, parseForwardedHeader, resolveOriginal, subjectMatches, } from "../src/lib/email.js"; import { matchRule } from "../src/handlers/match-rule.js"; import { briTransferDirectBody, briTransferForwardedBody, grabBody, grabForwardedBody, livinDirectBody, livinForwardedBody, } from "./fixtures.js"; const silentLog = { info() {}, warn() {}, error() {}, }; describe("extractEmail", () => { it("parses angle-bracket addresses", () => { assert.equal( extractEmail(`"Livin'" `), "noreply.livin@bankmandiri.co.id", ); }); }); describe("parseForwardedHeader", () => { it("reads original From/Subject from a Fwd block", () => { const h = parseForwardedHeader(livinForwardedBody); assert.ok(h); assert.match(h.from, /noreply\.livin@bankmandiri\.co\.id/); assert.equal(h.subject, "Pembayaran Berhasil!"); }); it("returns null when there is no Fwd block", () => { assert.equal(parseForwardedHeader(livinDirectBody), null); }); }); describe("resolveOriginal", () => { it("uses envelope for direct mail", () => { const o = resolveOriginal({ from: `"Livin'" `, subject: "Pembayaran Berhasil!", date: "Sun, 13 Sep 2026 14:48:36 +0700 (WIB)", body: livinDirectBody, }); assert.equal(o.viaForward, false); assert.equal(extractEmail(o.from), "noreply.livin@bankmandiri.co.id"); }); it("uses Fwd header for forwarded mail", () => { const o = resolveOriginal({ from: "NSRB ", subject: "Fwd: Your Grab E-Receipt", body: grabForwardedBody, }); assert.equal(o.viaForward, true); assert.equal(extractEmail(o.from), "no-reply@grab.com"); assert.equal(o.subject, "Your Grab E-Receipt"); }); }); describe("subjectMatches", () => { it("matches exact and Fwd-prefixed subjects", () => { assert.equal(subjectMatches("Pembayaran Berhasil!", "Pembayaran Berhasil!"), true); assert.equal(subjectMatches("Fwd: Pembayaran Berhasil!", "Pembayaran Berhasil!"), true); assert.equal(subjectMatches("Hello", "Pembayaran Berhasil!"), false); }); }); describe("matchRule", () => { it("matches direct Livin", async () => { const result = await matchRule({ messageId: "1a099bd61efd234d", log: silentLog, message: { from: `"Livin'" `, subject: "Pembayaran Berhasil!", date: "Sun, 13 Sep 2026 14:48:36 +0700 (WIB)", body: livinDirectBody, }, }); assert.equal(result.pass.rule.kind, "livin.qr_payment.success"); }); it("matches forwarded Livin via original header", async () => { const result = await matchRule({ messageId: "1a099b0c04c4397a", log: silentLog, message: { from: "NSRB ", subject: "Fwd: Pembayaran Berhasil!", body: livinForwardedBody, }, }); assert.equal(result.pass.rule.kind, "livin.qr_payment.success"); }); it("matches direct Grab", async () => { const result = await matchRule({ messageId: "grab-direct", log: silentLog, message: { from: "Grab ", subject: "Your Grab E-Receipt", body: grabBody, }, }); assert.equal(result.pass.rule.kind, "grab.ereceipt.ride"); }); it("matches forwarded Grab via original header", async () => { const result = await matchRule({ messageId: "1a099b8b9d239e5e", log: silentLog, message: { from: "NSRB ", subject: "Fwd: Your Grab E-Receipt", body: grabForwardedBody, }, }); assert.equal(result.pass.rule.kind, "grab.ereceipt.ride"); }); it("matches direct BRI transfer", async () => { const result = await matchRule({ messageId: "bri-direct", log: silentLog, message: { from: "Bank BRI ", subject: "Pemindahan Dana Sesama Rekening BRI", body: briTransferDirectBody, }, }); assert.equal(result.pass.rule.kind, "bri.transfer.success"); }); it("matches forwarded BRI transfer via original header", async () => { const result = await matchRule({ messageId: "1a09b6cd9a3bc6bd", log: silentLog, message: { from: "Nasyarobby Putra ", subject: "Fwd: Pemindahan Dana Sesama Rekening BRI", body: briTransferForwardedBody, }, }); assert.equal(result.pass.rule.kind, "bri.transfer.success"); }); it("breaks on unknown from/subject", async () => { const result = await matchRule({ messageId: "x", log: silentLog, message: { from: "Someone ", subject: "Hello", body: "hi", }, }); assert.equal(result.break, true); }); });