Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
322 lines
10 KiB
TypeScript
322 lines
10 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import {
|
|
stripForwardingHeaderBlock,
|
|
stripSubjectForwardingPrefix,
|
|
stripMailSignature,
|
|
getForwardedMailContent,
|
|
} from "./forwardedParser";
|
|
|
|
describe("forwardedParser", () => {
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("stripForwardingHeaderBlock", () => {
|
|
describe("returns original text when no forwarding separator is found", () => {
|
|
it("returns the original text for plain content", () => {
|
|
const text = "Hello, this is a regular email body.";
|
|
expect(stripForwardingHeaderBlock(text)).toBe(text);
|
|
});
|
|
|
|
it("trims whitespace when no separator is found", () => {
|
|
const text = " Hello world ";
|
|
expect(stripForwardingHeaderBlock(text)).toBe("Hello world");
|
|
});
|
|
|
|
it("returns original text when separator is not on the first line", () => {
|
|
const text =
|
|
"Some intro line\n---------- Forwarded message ----------\nActual content";
|
|
expect(stripForwardingHeaderBlock(text)).toBe(text.trim());
|
|
});
|
|
});
|
|
|
|
describe("Gmail forwarded separator", () => {
|
|
it("strips the Gmail forwarded header block", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@example.com>",
|
|
"Date: Mon, 24 Feb 2026 10:00:00 +0000",
|
|
"Subject: Meeting notes",
|
|
"To: Bob <bob@example.com>",
|
|
"",
|
|
"Hi Bob,",
|
|
"",
|
|
"Here are the meeting notes.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"Hi Bob,\n\nHere are the meeting notes.",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Apple Mail forwarded separator", () => {
|
|
it("strips the Apple Mail forwarded header block", () => {
|
|
const text = [
|
|
"Begin forwarded message:",
|
|
"From: Alice <alice@example.com>",
|
|
"Subject: Hello",
|
|
"Date: 24 Feb 2026",
|
|
"To: Bob <bob@example.com>",
|
|
"",
|
|
"This is the original message.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"This is the original message.",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Outlook / Exchange forwarded separator", () => {
|
|
it("strips the Outlook forwarded header block", () => {
|
|
const text = [
|
|
"-----Original Message-----",
|
|
"From: Alice <alice@example.com>",
|
|
"Sent: Monday, February 24, 2026 10:00 AM",
|
|
"To: Bob <bob@example.com>",
|
|
"Subject: Project update",
|
|
"",
|
|
"Please find the update below.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"Please find the update below.",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("French forwarded separators", () => {
|
|
it("strips the 'Message transféré' header block", () => {
|
|
const text = [
|
|
"---------- Message transféré ----------",
|
|
"De : Alice <alice@example.com>",
|
|
"Date : 24 févr. 2026",
|
|
"Objet : Réunion",
|
|
"",
|
|
"Bonjour,",
|
|
"",
|
|
"Voici le message.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"Bonjour,\n\nVoici le message.",
|
|
);
|
|
});
|
|
|
|
it("strips the 'Transféré' header block", () => {
|
|
const text = [
|
|
"----- Transféré -----",
|
|
"De : Alice <alice@example.com>",
|
|
"",
|
|
"Le message transféré.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe("Le message transféré.");
|
|
});
|
|
|
|
it("strips the ASCII-variant 'Message transfere' header block", () => {
|
|
const text = [
|
|
"---------- Message transfere ----------",
|
|
"De : Alice <alice@example.com>",
|
|
"",
|
|
"Bonjour.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe("Bonjour.");
|
|
});
|
|
});
|
|
|
|
describe("German forwarded separator", () => {
|
|
it("strips the 'Weitergeleitete Nachricht' header block", () => {
|
|
const text = [
|
|
"---------- Weitergeleitete Nachricht ----------",
|
|
"Von: Alice <alice@example.com>",
|
|
"Datum: 24. Feb. 2026",
|
|
"Betreff: Projekt",
|
|
"",
|
|
"Hallo,",
|
|
"",
|
|
"Hier ist die Nachricht.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"Hallo,\n\nHier ist die Nachricht.",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("edge cases", () => {
|
|
it("strip everything when there is only one forwarded block and nothing after", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@example.com>",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe("");
|
|
});
|
|
|
|
it("preserves multi-paragraph body content", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@example.com>",
|
|
"",
|
|
"First paragraph.",
|
|
"",
|
|
"Second paragraph.",
|
|
"",
|
|
"Third paragraph.",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe(
|
|
"First paragraph.\n\nSecond paragraph.\n\nThird paragraph.",
|
|
);
|
|
});
|
|
|
|
it("trims leading and trailing whitespace from the result", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice",
|
|
"",
|
|
" ",
|
|
" Body content ",
|
|
" ",
|
|
].join("\n");
|
|
|
|
expect(stripForwardingHeaderBlock(text)).toBe("Body content");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("stripSubjectForwardingPrefix", () => {
|
|
it("strips 'Fwd:' prefix", () => {
|
|
expect(stripSubjectForwardingPrefix("Fwd: Hello")).toBe("Hello");
|
|
});
|
|
|
|
it("strips 'FW:' prefix", () => {
|
|
expect(stripSubjectForwardingPrefix("FW: Hello")).toBe("Hello");
|
|
});
|
|
|
|
it("strips 'FWD:' prefix", () => {
|
|
expect(stripSubjectForwardingPrefix("FWD: Hello")).toBe("Hello");
|
|
});
|
|
|
|
it("strips 'Tr:' prefix (French)", () => {
|
|
expect(stripSubjectForwardingPrefix("Tr: Bonjour")).toBe("Bonjour");
|
|
});
|
|
|
|
it("strips 'SV:' prefix (Scandinavian)", () => {
|
|
expect(stripSubjectForwardingPrefix("SV: Hei")).toBe("Hei");
|
|
});
|
|
|
|
it("strips 'VS:' prefix", () => {
|
|
expect(stripSubjectForwardingPrefix("VS: Hallo")).toBe("Hallo");
|
|
});
|
|
|
|
it("strips 'WG:' prefix (German)", () => {
|
|
expect(stripSubjectForwardingPrefix("WG: Hallo")).toBe("Hallo");
|
|
});
|
|
|
|
it("is case-insensitive", () => {
|
|
expect(stripSubjectForwardingPrefix("fwd: lowercase")).toBe("lowercase");
|
|
expect(stripSubjectForwardingPrefix("FWD - Mixed")).toBe("Mixed");
|
|
});
|
|
|
|
it("returns the subject unchanged when no prefix is present", () => {
|
|
expect(stripSubjectForwardingPrefix("Meeting notes")).toBe(
|
|
"Meeting notes",
|
|
);
|
|
});
|
|
|
|
it("handles dash separator instead of colon", () => {
|
|
expect(stripSubjectForwardingPrefix("Fwd - My subject")).toBe(
|
|
"My subject",
|
|
);
|
|
});
|
|
|
|
it("should return original subject if stripping results in empty string", () => {
|
|
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
const subject = "Fwd: ";
|
|
expect(stripSubjectForwardingPrefix(subject)).toBe(subject);
|
|
});
|
|
});
|
|
|
|
describe("stripMailSignature", () => {
|
|
it("strips the mail signature when separator is present", () => {
|
|
const text = "Hello,\nThis is the email body.\n-- \nSignature here";
|
|
expect(stripMailSignature(text)).toBe("Hello,\nThis is the email body.");
|
|
});
|
|
|
|
it("returns original text when no signature separator is found", () => {
|
|
const text = "Hello,\nThis is the email body.\nBest regards.";
|
|
expect(stripMailSignature(text)).toBe(text);
|
|
});
|
|
|
|
it("handles multiple occurrences of the signature separator", () => {
|
|
const text =
|
|
"Hello,\nThis is the email body.\n-- \nFirst signature\n-- \nSecond signature";
|
|
expect(stripMailSignature(text)).toBe("Hello,\nThis is the email body.");
|
|
});
|
|
|
|
it("trims whitespace from the result", () => {
|
|
const text = "Hello,\nThis is the email body.\n-- \nSignature here ";
|
|
expect(stripMailSignature(text)).toBe("Hello,\nThis is the email body.");
|
|
});
|
|
});
|
|
|
|
describe("getForwardedMailContent", () => {
|
|
it("strips both the forwarding header block and the mail signature", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@wonderland.com>",
|
|
"",
|
|
"Hi Bob,",
|
|
"This is the original message.",
|
|
"-- \nAlice's signature",
|
|
].join("\n");
|
|
|
|
expect(getForwardedMailContent(text)).toBe(
|
|
"Hi Bob,\nThis is the original message.",
|
|
);
|
|
});
|
|
|
|
it("returns original text when stripping results in empty content", () => {
|
|
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@wonderland.com>",
|
|
"",
|
|
"-- \nAlice's signature",
|
|
].join("\n");
|
|
|
|
// Both stripping operations would result in empty content, so original text should be returned.
|
|
expect(getForwardedMailContent(text)).toBe(text.trim());
|
|
});
|
|
|
|
it("handles text with no forwarding header and no signature", () => {
|
|
const text = "Hello,\nThis is a simple email body.";
|
|
expect(getForwardedMailContent(text)).toBe(text);
|
|
});
|
|
|
|
it("handles text with only a forwarding header", () => {
|
|
const text = [
|
|
"---------- Forwarded message ----------",
|
|
"From: Alice <alice@wonderland.com>",
|
|
"",
|
|
"This is the original message.",
|
|
].join("\n");
|
|
|
|
expect(getForwardedMailContent(text)).toBe(
|
|
"This is the original message.",
|
|
);
|
|
});
|
|
|
|
it("handles text with only a mail signature", () => {
|
|
const text = "Hello,\nThis is the email body.\n-- \nBest regards.";
|
|
expect(getForwardedMailContent(text)).toBe(
|
|
"Hello,\nThis is the email body.",
|
|
);
|
|
});
|
|
});
|
|
});
|