import net from "node:net"; import { afterEach, describe, expect, it } from "vitest"; import type { CatalogComponent, FlowNode } from "../types"; import type { RunContext } from "../engine/types"; import { getHandler, hasCapability } from "../engine/registry"; import "./message"; const context = {} as RunContext; const component = {} as CatalogComponent; const node = (id: string): FlowNode => ({ id, componentId: id, position: { x: 0, y: 0 }, values: {}, options: {} }); const ids = [ "Mail_FindMail", "Mail_FindMail_v1", "Mail_FindMail_v2", "Mail_ReplyMail", "Mail_ReplyMail_v1", "Mail_ReplyMail_v2", "Mail_DoGetMailMessage", "Mail_DoGetMailMessage_v1", "Mail_DoGetMailMessage_v2" ]; afterEach(async () => {}); describe("mail receive and reply", () => { it("registers find, reply and Outlook message capabilities", () => { for (const id of ids) expect(hasCapability(id), id).toBe(true); }); it("replies through SMTP with the selected mail sender", async () => { let received = ""; const server = net.createServer((socket) => { socket.setEncoding("utf8"); socket.write("220 localhost ESMTP\r\n"); let buffer = ""; let dataMode = false; socket.on("data", (chunk) => { buffer += chunk; const lines = buffer.split("\r\n"); buffer = lines.pop() || ""; for (const line of lines) { if (dataMode) { if (line === ".") { dataMode = false; socket.write("250 queued\r\n"); } else received += line + "\n"; } else if (/^EHLO/i.test(line)) socket.write("250-localhost\r\n250 OK\r\n"); else if (/^MAIL FROM/i.test(line)) socket.write("250 ok\r\n"); else if (/^RCPT TO/i.test(line)) socket.write("250 ok\r\n"); else if (/^DATA/i.test(line)) { dataMode = true; socket.write("354 end with dot\r\n"); } else if (/^QUIT/i.test(line)) { socket.write("221 bye\r\n"); socket.end(); } else socket.write("250 OK\r\n"); } }); }); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); const port = (server.address() as net.AddressInfo).port; try { const handler = getHandler("Mail_ReplyMail_v2"); expect(handler).toBeTruthy(); const result = await handler!(context, node("Mail_ReplyMail_v2"), { account_obj: { host: "127.0.0.1", port, account: "robot@example.com", secure: "False" }, mail_obj: { from: "owner@example.com", subject: "status", messageId: "" }, content: "reply delivered" }, component); expect(result).toMatchObject({ accepted: ["owner@example.com"] }); expect(received).toContain("reply delivered"); expect(received).toContain("Re: status"); } finally { await new Promise((resolve) => server.close(() => resolve())); } }, 30000); });