文件
hyb-oa/server/tests/unit/services/email.test.js
T

163 行
5.0 KiB
JavaScript

const {
resolveEmailDeliveryStatus,
sendNotificationEmail,
} = require("../../../src/services/email");
function buildEmailConfig(overrides = {}) {
return {
emailEnabled: true,
emailFrom: "[email protected]",
emailBaseUrl: "https://oa.hyinda.test/",
appOrigin: "",
smtpHost: "smtp.hyinda.test",
smtpPort: 587,
smtpSecure: false,
smtpUser: "sender",
smtpPass: "test-only-password",
...overrides,
};
}
describe("email delivery status", () => {
it("reports ready only when SMTP delivery has the required public settings", () => {
expect(
resolveEmailDeliveryStatus({
emailEnabled: true,
emailFrom: "[email protected]",
smtpHost: "smtp.hyinda.test",
smtpPort: 587,
smtpSecure: false,
smtpUser: "",
smtpPass: "",
}),
).toEqual({
ready: true,
reasons: [],
});
});
it("reports non-secret missing SMTP reasons", () => {
expect(
resolveEmailDeliveryStatus({
emailEnabled: true,
emailFrom: "",
smtpHost: "",
smtpPort: 0,
smtpSecure: false,
smtpUser: "sender",
smtpPass: "",
}),
).toEqual({
ready: false,
reasons: ["email_from_missing", "smtp_host_missing", "smtp_port_invalid", "smtp_auth_incomplete"],
});
});
});
describe("notification email delivery", () => {
it("skips delivery without creating a transporter when email is disabled", async () => {
const createTransport = vi.fn();
const prisma = { employee: { findMany: vi.fn() } };
const result = await sendNotificationEmail({
prisma,
config: buildEmailConfig({ emailEnabled: false }),
recipientEmployeeIds: ["employee-1"],
subject: "待办提醒",
body: "请处理待办。",
createTransport,
});
expect(result).toEqual({ skipped: true, sent: 0, failed: 0 });
expect(createTransport).not.toHaveBeenCalled();
expect(prisma.employee.findMany).not.toHaveBeenCalled();
});
it("creates a Nodemailer 9 transporter and sends text mail with a safe link", async () => {
const sendMail = vi.fn(async () => ({ messageId: "message-1" }));
const createTransport = vi.fn(() => ({ sendMail }));
const prisma = {
employee: {
findMany: vi.fn(async () => [
{ id: "employee-1", email: "[email protected]", name: "员工一" },
{ id: "employee-2", email: null, name: "员工二" },
]),
},
};
const result = await sendNotificationEmail({
prisma,
config: buildEmailConfig({ smtpHost: "smtp-success.hyinda.test" }),
recipientEmployeeIds: ["employee-1", "employee-2", "employee-1"],
subject: "待办提醒",
body: "请处理待办。",
type: "workflow_task",
targetPath: "/workflows/tasks/1",
requestId: "request-1",
createTransport,
});
expect(createTransport).toHaveBeenCalledWith({
host: "smtp-success.hyinda.test",
port: 587,
secure: false,
auth: { user: "sender", pass: "test-only-password" },
});
expect(sendMail).toHaveBeenCalledWith({
from: "[email protected]",
to: "[email protected]",
subject: "待办提醒",
text: "请处理待办。\n\n查看详情:https://oa.hyinda.test/workflows/tasks/1",
headers: {
"x-hyb-notification-type": "workflow_task",
"x-request-id": "request-1",
},
});
expect(result).toEqual({ skipped: false, sent: 1, failed: 1 });
});
it("counts send failures without logging the recipient email address", async () => {
const error = new Error("smtp_rejected");
error.code = "EENVELOPE";
error.command = "RCPT TO";
error.responseCode = 550;
error.response = "550 rejected [email protected]";
error.rejected = ["[email protected]"];
const createTransport = vi.fn(() => ({ sendMail: vi.fn(async () => { throw error; }) }));
const logger = { error: vi.fn() };
const prisma = {
employee: {
findMany: vi.fn(async () => [
{ id: "employee-3", email: "[email protected]", name: "员工三" },
]),
},
};
const result = await sendNotificationEmail({
prisma,
config: buildEmailConfig({ smtpHost: "smtp-failure.hyinda.test" }),
logger,
requestId: "request-2",
recipientEmployeeIds: ["employee-3"],
subject: "待办提醒",
body: "请处理待办。",
createTransport,
});
expect(result).toEqual({ skipped: false, sent: 0, failed: 1 });
expect(logger.error).toHaveBeenCalledOnce();
const [context] = logger.error.mock.calls[0];
expect(context).toMatchObject({
errorCode: "email_delivery_failed",
providerCode: "EENVELOPE",
smtpCommand: "RCPT TO",
smtpResponseCode: 550,
requestId: "request-2",
employeeId: "employee-3",
});
expect(context).not.toHaveProperty("err");
expect(context).not.toHaveProperty("email");
expect(JSON.stringify(context)).not.toContain("[email protected]");
});
});