163 行
5.0 KiB
JavaScript
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]");
|
|
});
|
|
});
|