aboutsummaryrefslogtreecommitdiff
path: root/deno/mail-relay/mail.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'deno/mail-relay/mail.test.ts')
-rw-r--r--deno/mail-relay/mail.test.ts143
1 files changed, 143 insertions, 0 deletions
diff --git a/deno/mail-relay/mail.test.ts b/deno/mail-relay/mail.test.ts
new file mode 100644
index 0000000..ee275af
--- /dev/null
+++ b/deno/mail-relay/mail.test.ts
@@ -0,0 +1,143 @@
+import { describe, it } from "@std/testing/bdd";
+import { expect, fn } from "@std/expect";
+
+import { Mail, MailDeliverContext, MailDeliverer } from "./mail.ts";
+
+const mockDate = "Fri, 02 May 2025 08:33:02 +0000";
+const mockMessageId = "mock-message-id@from.mock";
+const mockMessageId2 = "mock-message-id-2@from.mock";
+const mockFromAddress = "mock@from.mock";
+const mockCcAddress = "mock@cc.mock";
+const mockBodyStr = `This is body content.
+Line 2 ${mockMessageId2}
+
+Line 4`;
+const mockHeaders = [
+ ["Content-Disposition", "inline"],
+ ["Content-Transfer-Encoding", "quoted-printable"],
+ ["MIME-Version", "1.0"],
+ ["X-Mailer", "MIME-tools 5.509 (Entity 5.509)"],
+ ["Content-Type", "text/plain; charset=utf-8"],
+ ["From", `"Mock From" <${mockFromAddress}>`],
+ [
+ "To",
+ `"John \\"Big\\" Doe" <john@example.com>, "Alice (Work)" <alice+work@example.com>,
+ undisclosed-recipients:;, "Group: Team" <team@company.com>,
+ "Escaped, Name" <escape@test.com>, just@email.com,
+ "Comment (This is valid)" <comment@domain.net>,
+ "Odd @Chars" <weird!#$%'*+-/=?^_\`{|}~@char-test.com>,
+ "Non-ASCII 用户" <user@例子.中国>,
+ admin@[192.168.1.1]`,
+ ],
+ ["CC", `Mock CC <${mockCcAddress}>`],
+ ["Subject", "A very long mock\n subject"],
+ ["Message-ID", `<${mockMessageId}>`],
+ ["Date", mockDate],
+];
+const mockHeaderStr = mockHeaders.map((h) => h[0] + ": " + h[1]).join("\n");
+const mockMailStr = mockHeaderStr + "\n\n" + mockBodyStr;
+const mockCrlfMailStr = mockMailStr.replaceAll("\n", "\r\n");
+const mockToAddresses = [
+ "john@example.com",
+ "alice+work@example.com",
+ "team@company.com",
+ "escape@test.com",
+ "just@email.com",
+ "comment@domain.net",
+ "weird!#$%'*+-/=?^_`{|}~@char-test.com",
+ "user@例子.中国",
+ "admin@[192.168.1.1]",
+];
+
+describe("Mail", () => {
+ it("simple parse", () => {
+ const parsed = new Mail(mockMailStr).startSimpleParse().sections();
+ expect(parsed.header).toEqual(mockHeaderStr);
+ expect(parsed.body).toEqual(mockBodyStr);
+ expect(parsed.sep).toBe("\n");
+ expect(parsed.eol).toBe("\n");
+ });
+
+ it("simple parse crlf", () => {
+ const parsed = new Mail(mockCrlfMailStr).startSimpleParse().sections();
+ expect(parsed.sep).toBe("\r\n");
+ expect(parsed.eol).toBe("\r\n");
+ });
+
+ it("simple parse date", () => {
+ expect(new Mail(mockMailStr).startSimpleParse().sections().headers().date())
+ .toEqual(new Date(mockDate));
+ });
+
+ it("simple parse headers", () => {
+ expect(
+ new Mail(mockMailStr).startSimpleParse().sections().headers(),
+ ).toEqual(mockHeaders.map(
+ (h) => [h[0], " " + h[1].replaceAll("\n", "")],
+ ));
+ });
+
+ it("append headers", () => {
+ const mail = new Mail(mockMailStr);
+ const mockMoreHeaders = [["abc", "123"], ["def", "456"]] satisfies [
+ string,
+ string,
+ ][];
+ mail.appendHeaders(mockMoreHeaders);
+
+ expect(mail.raw).toBe(
+ mockHeaderStr + "\n" +
+ mockMoreHeaders.map((h) => h[0] + ": " + h[1]).join("\n") +
+ "\n\n" + mockBodyStr,
+ );
+ });
+
+ it("parse recipients", () => {
+ const mail = new Mail(mockMailStr);
+ expect([...mail.startSimpleParse().sections().headers().recipients()])
+ .toEqual([
+ ...mockToAddresses,
+ mockCcAddress,
+ ]);
+ expect([
+ ...mail.startSimpleParse().sections().headers().recipients({
+ domain: "example.com",
+ }),
+ ]).toEqual([
+ ...mockToAddresses,
+ mockCcAddress,
+ ].filter((a) => a.endsWith("example.com")));
+ });
+
+ it("find all addresses", () => {
+ const mail = new Mail(mockMailStr);
+ expect(mail.simpleFindAllAddresses()).toEqual([
+ "mock@from.mock",
+ "john@example.com",
+ "alice+work@example.com",
+ "team@company.com",
+ "escape@test.com",
+ "just@email.com",
+ "comment@domain.net",
+ "mock@cc.mock",
+ "mock-message-id@from.mock",
+ "mock-message-id-2@from.mock",
+ ]);
+ });
+});
+
+describe("MailDeliverer", () => {
+ class MockMailDeliverer extends MailDeliverer {
+ name = "mock";
+ override doDeliver = fn((_: Mail, ctx: MailDeliverContext) => {
+ ctx.result.recipients.set("*", { kind: "done", message: "success" });
+ return Promise.resolve();
+ }) as MailDeliverer["doDeliver"];
+ }
+ const mockDeliverer = new MockMailDeliverer();
+
+ it("deliver success", async () => {
+ await mockDeliverer.deliverRaw(mockMailStr);
+ expect(mockDeliverer.doDeliver).toHaveBeenCalledTimes(1);
+ });
+});