feat: implement comprehensive notification engine with policies, preferences, and automated dispatching services
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
import mongoose from "mongoose";
|
||||
import { buildNotificationText, resolveNotificationContent } from "../NotificationContentResolver.js";
|
||||
|
||||
describe("NotificationContentResolver", () => {
|
||||
it("builds appointment creation subject and message as Alta de turno", () => {
|
||||
const result = buildNotificationText({
|
||||
type: "creation",
|
||||
appointment: {
|
||||
_id: "appointment-1",
|
||||
companyId: "company-1",
|
||||
start: new Date("2026-07-22T15:30:00.000Z"),
|
||||
},
|
||||
service: { _id: "service-1", name: "Corte" },
|
||||
company: { _id: "company-1", name: "Barber Shop" },
|
||||
});
|
||||
|
||||
expect(result.subject).toContain("Alta de turno");
|
||||
expect(result.subject).toContain("Barber Shop");
|
||||
expect(result.message).toContain("Corte");
|
||||
expect(result.message).toContain("confirmado");
|
||||
});
|
||||
|
||||
it("builds meaningful appointment reminder subject and message", () => {
|
||||
const result = buildNotificationText({
|
||||
type: "reminder",
|
||||
appointment: {
|
||||
_id: "appointment-1",
|
||||
companyId: "company-1",
|
||||
start: new Date("2026-07-22T15:30:00.000Z"),
|
||||
},
|
||||
service: { _id: "service-1", name: "Corte" },
|
||||
company: { _id: "company-1", name: "Barber Shop" },
|
||||
});
|
||||
|
||||
expect(result.subject).toContain("Recordatorio");
|
||||
expect(result.subject).toContain("Barber Shop");
|
||||
expect(result.message).toContain("Corte");
|
||||
expect(result.message).toContain("Barber Shop");
|
||||
expect(result.subject.trim()).not.toBe("");
|
||||
expect(result.message.trim()).not.toBe("");
|
||||
});
|
||||
|
||||
it("uses cancellation snapshot payload without requiring appointment lookup", async () => {
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "deleted-appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "email",
|
||||
type: "cancellation",
|
||||
payload: {
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Turno cancelado en Barber Shop",
|
||||
message: "Tu turno para Corte fue cancelado.",
|
||||
emailSubject: "Email cancellation subject",
|
||||
emailMessage: "Email cancellation body.",
|
||||
wapMessage: "WAP cancellation body.",
|
||||
systemSubject: "System cancellation subject",
|
||||
systemMessage: "System cancellation body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(result).toEqual({
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Email cancellation subject",
|
||||
message: "Email cancellation body.",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses creation snapshot payload content for email jobs", async () => {
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "email",
|
||||
type: "creation",
|
||||
payload: {
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Turno reservado en Barber Shop",
|
||||
message: "Generic creation body.",
|
||||
emailSubject: "Email Alta subject",
|
||||
emailMessage: "Email Alta body.",
|
||||
wapMessage: "WAP Alta body.",
|
||||
systemSubject: "System Alta subject",
|
||||
systemMessage: "System Alta body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(result).toEqual({
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Email Alta subject",
|
||||
message: "Email Alta body.",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses creation snapshot payload content for WhatsApp jobs", async () => {
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "whatsapp",
|
||||
type: "creation",
|
||||
payload: {
|
||||
phoneNumber: "5491112345678",
|
||||
subject: "Generic subject",
|
||||
message: "Generic message.",
|
||||
emailMessage: "Email Alta body.",
|
||||
wapMessage: "WAP Alta body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(result.message).toBe("WAP Alta body.");
|
||||
});
|
||||
|
||||
it("uses reminder payload content without requiring appointment lookup", async () => {
|
||||
const appointmentLookup = jest.spyOn(mongoose.models.Appointment, "findOne");
|
||||
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "whatsapp",
|
||||
type: "reminder",
|
||||
payload: {
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Generic reminder subject",
|
||||
message: "Generic reminder body.",
|
||||
emailSubject: "Email reminder subject",
|
||||
emailMessage: "Email reminder body.",
|
||||
wapMessage: "WAP reminder body.",
|
||||
systemSubject: "System reminder subject",
|
||||
systemMessage: "System reminder body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(appointmentLookup).not.toHaveBeenCalled();
|
||||
expect(result).toEqual({
|
||||
email: "client@example.com",
|
||||
phoneNumber: "5491112345678",
|
||||
userId: "user-1",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Generic reminder subject",
|
||||
message: "WAP reminder body.",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses WhatsApp cancellation payload content for WhatsApp jobs", async () => {
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "deleted-appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "whatsapp",
|
||||
type: "cancellation",
|
||||
payload: {
|
||||
phoneNumber: "5491112345678",
|
||||
companyOwnerId: "owner-1",
|
||||
subject: "Generic subject",
|
||||
message: "Generic message.",
|
||||
emailMessage: "Email cancellation body.",
|
||||
wapMessage: "WAP cancellation body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(result.message).toBe("WAP cancellation body.");
|
||||
});
|
||||
|
||||
it("uses system cancellation payload content for system jobs", async () => {
|
||||
const result = await resolveNotificationContent({
|
||||
appointmentId: "deleted-appointment-1",
|
||||
clientId: "client-1",
|
||||
companyId: "company-1",
|
||||
channel: "system",
|
||||
type: "cancellation",
|
||||
payload: {
|
||||
userId: "user-1",
|
||||
subject: "Generic subject",
|
||||
message: "Generic message.",
|
||||
systemSubject: "System cancellation subject",
|
||||
systemMessage: "System cancellation body.",
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(result.subject).toBe("System cancellation subject");
|
||||
expect(result.message).toBe("System cancellation body.");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user