104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
/// <reference types="jest" />
|
|
|
|
import { NotificationsService } from "../src/notifications/notifications.service";
|
|
import { createPrismaMock } from "./utils/mock-prisma";
|
|
|
|
describe("NotificationsService", () => {
|
|
const userId = "user-1";
|
|
let prisma: ReturnType<typeof createPrismaMock>;
|
|
let emailService: { sendNotificationEmail: jest.Mock };
|
|
let service: NotificationsService;
|
|
|
|
beforeEach(() => {
|
|
prisma = createPrismaMock();
|
|
emailService = { sendNotificationEmail: jest.fn().mockResolvedValue(undefined) };
|
|
service = new NotificationsService(prisma as never, emailService as never);
|
|
|
|
prisma.notification.create.mockResolvedValue({
|
|
id: "notification-1",
|
|
userId,
|
|
type: "test",
|
|
severity: "info",
|
|
title: "Test",
|
|
body: "Body",
|
|
channels: ["in_app"],
|
|
});
|
|
prisma.notification.update.mockImplementation(({ data }) => Promise.resolve({ id: "notification-1", ...data }));
|
|
prisma.notificationPreference.findUnique.mockResolvedValue({
|
|
userId,
|
|
emailEnabled: true,
|
|
pushEnabled: false,
|
|
minSeverity: "info",
|
|
});
|
|
prisma.user.findUnique.mockResolvedValue({ email: "user@example.com" });
|
|
});
|
|
|
|
it("creates an in-app notification and sends SMTP email when enabled", async () => {
|
|
const result = await service.notifyUser(userId, {
|
|
type: "test",
|
|
title: "Test",
|
|
body: "Body",
|
|
});
|
|
|
|
expect(prisma.notification.create).toHaveBeenCalledWith(expect.objectContaining({
|
|
data: expect.objectContaining({ userId, channels: ["in_app"] }),
|
|
}));
|
|
expect(emailService.sendNotificationEmail).toHaveBeenCalledWith(
|
|
"user@example.com",
|
|
"Test",
|
|
"Body",
|
|
expect.stringContaining("/notifications"),
|
|
"info",
|
|
);
|
|
expect(result.channels).toEqual(["in_app", "email"]);
|
|
});
|
|
|
|
it("does not send email below the configured severity threshold", async () => {
|
|
prisma.notificationPreference.findUnique.mockResolvedValue({
|
|
userId,
|
|
emailEnabled: true,
|
|
pushEnabled: false,
|
|
minSeverity: "critical",
|
|
});
|
|
|
|
await service.notifyUser(userId, {
|
|
type: "test",
|
|
severity: "warning",
|
|
title: "Warning",
|
|
body: "Body",
|
|
});
|
|
|
|
expect(emailService.sendNotificationEmail).not.toHaveBeenCalled();
|
|
expect(prisma.notification.update).toHaveBeenCalledWith(expect.objectContaining({
|
|
data: { channels: ["in_app"] },
|
|
}));
|
|
});
|
|
|
|
it("stores a push subscription and enables push preferences", async () => {
|
|
prisma.pushSubscription.upsert.mockResolvedValue({ id: "push-1", userId });
|
|
prisma.notificationPreference.upsert.mockResolvedValue({
|
|
userId,
|
|
emailEnabled: true,
|
|
pushEnabled: true,
|
|
minSeverity: "info",
|
|
});
|
|
|
|
await service.savePushSubscription(
|
|
userId,
|
|
{
|
|
endpoint: "https://push.example.test/sub",
|
|
keys: { p256dh: "p256dh", auth: "auth" },
|
|
},
|
|
"jest",
|
|
);
|
|
|
|
expect(prisma.pushSubscription.upsert).toHaveBeenCalledWith(expect.objectContaining({
|
|
create: expect.objectContaining({ userId, userAgent: "jest" }),
|
|
update: expect.objectContaining({ userId, revokedAt: null }),
|
|
}));
|
|
expect(prisma.notificationPreference.upsert).toHaveBeenCalledWith(expect.objectContaining({
|
|
update: { pushEnabled: true },
|
|
}));
|
|
});
|
|
});
|