Implement parsing for BRI QRIS transactions, including direct and forwarded message handling. Update rules to recognize QRIS success messages and adjust spending record mapping accordingly. Enhance tests to cover new functionality.
200 lines
5.7 KiB
JavaScript
200 lines
5.7 KiB
JavaScript
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 {
|
|
briQrisDirectBody,
|
|
briQrisForwardedBody,
|
|
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>`),
|
|
"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'" <noreply.livin@bankmandiri.co.id>`,
|
|
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 <nasyarobby@gmail.com>",
|
|
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'" <noreply.livin@bankmandiri.co.id>`,
|
|
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 <nasyarobby@gmail.com>",
|
|
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 <no-reply@grab.com>",
|
|
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 <nasyarobby@gmail.com>",
|
|
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 <BankBRI@bri.co.id>",
|
|
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 <nsrb@bu.edu>",
|
|
subject: "Fwd: Pemindahan Dana Sesama Rekening BRI",
|
|
body: briTransferForwardedBody,
|
|
},
|
|
});
|
|
assert.equal(result.pass.rule.kind, "bri.transfer.success");
|
|
});
|
|
|
|
it("matches direct BRI QRIS", async () => {
|
|
const result = await matchRule({
|
|
messageId: "bri-qris-direct",
|
|
log: silentLog,
|
|
message: {
|
|
from: "Bank BRI <BankBRI@bri.co.id>",
|
|
subject: "Pembelian QRIS Berhasil",
|
|
body: briQrisDirectBody,
|
|
},
|
|
});
|
|
assert.equal(result.pass.rule.kind, "bri.qris.success");
|
|
});
|
|
|
|
it("matches forwarded BRI QRIS via original header", async () => {
|
|
const result = await matchRule({
|
|
messageId: "1a09b9031c233407",
|
|
log: silentLog,
|
|
message: {
|
|
from: "Nasyarobby Putra <nsrb@bu.edu>",
|
|
subject: "Fwd: Pembelian QRIS Berhasil",
|
|
body: briQrisForwardedBody,
|
|
},
|
|
});
|
|
assert.equal(result.pass.rule.kind, "bri.qris.success");
|
|
});
|
|
|
|
it("breaks on unknown from/subject", async () => {
|
|
const result = await matchRule({
|
|
messageId: "x",
|
|
log: silentLog,
|
|
message: {
|
|
from: "Someone <other@example.com>",
|
|
subject: "Hello",
|
|
body: "hi",
|
|
},
|
|
});
|
|
assert.equal(result.break, true);
|
|
});
|
|
});
|