mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
test: cover guardian notification preferences
This commit is contained in:
1 parent
a78189b7f6
commit
be4ee9ac6d
2 files changed
+360
-2
No files matched your search
@@ -10,6 +10,7 @@ vi.mock("@/lib/db", () => ({
|
||||
upsert: vi.fn(),
|
||||
},
|
||||
user: { findUnique: vi.fn() },
|
||||
accountGrant: { findMany: vi.fn() },
|
||||
auditLog: { create: vi.fn() },
|
||||
$transaction: (...args: unknown[]) => transactionMock(...args),
|
||||
},
|
||||
@@ -32,15 +33,17 @@ vi.mock("@/lib/logging/context", () => ({
|
||||
}));
|
||||
|
||||
const sendViaWebPushMock = vi.fn();
|
||||
const sendViaNtfyMock = vi.fn();
|
||||
const sendViaApnsMock = vi.fn();
|
||||
|
||||
vi.mock("@/lib/notifications/senders/apns", () => ({
|
||||
sendViaApns: vi.fn(),
|
||||
sendViaApns: (...args: unknown[]) => sendViaApnsMock(...args),
|
||||
}));
|
||||
vi.mock("@/lib/notifications/senders/email", () => ({
|
||||
sendViaEmail: vi.fn(),
|
||||
}));
|
||||
vi.mock("@/lib/notifications/senders/ntfy", () => ({
|
||||
sendViaNtfy: vi.fn(),
|
||||
sendViaNtfy: (...args: unknown[]) => sendViaNtfyMock(...args),
|
||||
}));
|
||||
vi.mock("@/lib/notifications/senders/telegram", () => ({
|
||||
sendViaTelegram: vi.fn(),
|
||||
@@ -94,6 +97,8 @@ beforeEach(() => {
|
||||
}),
|
||||
);
|
||||
sendViaWebPushMock.mockResolvedValue({ ok: true });
|
||||
sendViaNtfyMock.mockResolvedValue({ ok: true });
|
||||
sendViaApnsMock.mockResolvedValue({ ok: true });
|
||||
});
|
||||
|
||||
describe("notification delivery identity", () => {
|
||||
@@ -180,4 +185,155 @@ describe("notification delivery identity", () => {
|
||||
);
|
||||
expect(sendViaWebPushMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders for each Guardian while isolating channel preferences", async () => {
|
||||
const firstGuardian = "guardian-en";
|
||||
const secondGuardian = "guardian-de";
|
||||
|
||||
(
|
||||
prisma.user.findUnique as unknown as ReturnType<typeof vi.fn>
|
||||
).mockImplementation(async ({ where }: { where: { id: string } }) => {
|
||||
if (where.id === recordUserId) {
|
||||
return { managedProfileAt: new Date() } as never;
|
||||
}
|
||||
if (where.id === firstGuardian) {
|
||||
return {
|
||||
managedProfileAt: null,
|
||||
locale: "en",
|
||||
notificationPrefs: { medication: { clientManaged: true } },
|
||||
} as never;
|
||||
}
|
||||
return {
|
||||
managedProfileAt: null,
|
||||
locale: "de",
|
||||
notificationPrefs: { medication: { clientManaged: true } },
|
||||
} as never;
|
||||
});
|
||||
vi.mocked(prisma.accountGrant.findMany).mockResolvedValue([
|
||||
{ granteeId: firstGuardian, grantee: { managedProfileAt: null } },
|
||||
{ granteeId: secondGuardian, grantee: { managedProfileAt: null } },
|
||||
] as never);
|
||||
(
|
||||
prisma.notificationChannel.findMany as unknown as ReturnType<typeof vi.fn>
|
||||
).mockImplementation(async ({ where }: { where: { userId: string } }) => {
|
||||
if (where.userId === firstGuardian) {
|
||||
return [
|
||||
{
|
||||
id: "first-web-disabled",
|
||||
userId: firstGuardian,
|
||||
type: "WEB_PUSH",
|
||||
config: "{}",
|
||||
nextRetryAt: null,
|
||||
preferences: [{ eventType: "MEDICATION_REMINDER", enabled: false }],
|
||||
},
|
||||
{
|
||||
id: "first-ntfy-enabled",
|
||||
userId: firstGuardian,
|
||||
type: "NTFY",
|
||||
config: "{}",
|
||||
nextRetryAt: null,
|
||||
preferences: [],
|
||||
},
|
||||
] as never;
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: "second-web-enabled",
|
||||
userId: secondGuardian,
|
||||
type: "WEB_PUSH",
|
||||
config: "{}",
|
||||
nextRetryAt: null,
|
||||
preferences: [],
|
||||
},
|
||||
{
|
||||
id: "second-ntfy-disabled",
|
||||
userId: secondGuardian,
|
||||
type: "NTFY",
|
||||
config: "{}",
|
||||
nextRetryAt: null,
|
||||
preferences: [{ eventType: "MEDICATION_REMINDER", enabled: false }],
|
||||
},
|
||||
] as never;
|
||||
});
|
||||
|
||||
const outcome = await dispatchNotification({
|
||||
eventType: "MEDICATION_REMINDER",
|
||||
userId: recordUserId,
|
||||
title: "record-language-title",
|
||||
message: "record-language-message",
|
||||
renderForRecipient: (locale) => ({
|
||||
title: `title-${locale}`,
|
||||
message: `message-${locale}`,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(outcome).toEqual({
|
||||
dispatched: true,
|
||||
channelsAttempted: 2,
|
||||
channelsSucceeded: 2,
|
||||
});
|
||||
expect(sendViaNtfyMock).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({
|
||||
recipientUserId: firstGuardian,
|
||||
title: "title-en",
|
||||
message: "message-en",
|
||||
}),
|
||||
);
|
||||
expect(sendViaWebPushMock).toHaveBeenCalledWith(
|
||||
secondGuardian,
|
||||
expect.objectContaining({
|
||||
recipientUserId: secondGuardian,
|
||||
title: "title-de",
|
||||
message: "message-de",
|
||||
}),
|
||||
);
|
||||
expect(sendViaWebPushMock).toHaveBeenCalledTimes(1);
|
||||
expect(sendViaNtfyMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("bypasses client-managed APNs suppression only for managed Guardian delivery", async () => {
|
||||
const guardian = "guardian-apns";
|
||||
(
|
||||
prisma.user.findUnique as unknown as ReturnType<typeof vi.fn>
|
||||
).mockImplementation(
|
||||
async ({ where }: { where: { id: string } }) =>
|
||||
(where.id === recordUserId
|
||||
? { managedProfileAt: new Date() }
|
||||
: {
|
||||
managedProfileAt: null,
|
||||
notificationPrefs: { medication: { clientManaged: true } },
|
||||
}) as never,
|
||||
);
|
||||
vi.mocked(prisma.accountGrant.findMany).mockResolvedValue([
|
||||
{ granteeId: guardian, grantee: { managedProfileAt: null } },
|
||||
] as never);
|
||||
vi.mocked(prisma.notificationChannel.findMany).mockResolvedValue([
|
||||
{
|
||||
id: "guardian-apns",
|
||||
userId: guardian,
|
||||
type: "APNS",
|
||||
config: "{}",
|
||||
nextRetryAt: null,
|
||||
preferences: [],
|
||||
},
|
||||
] as never);
|
||||
|
||||
await expect(
|
||||
dispatchNotification({
|
||||
eventType: "MEDICATION_REMINDER",
|
||||
userId: recordUserId,
|
||||
title: "Record content",
|
||||
message: "Record schedule",
|
||||
}),
|
||||
).resolves.toMatchObject({ dispatched: true, channelsSucceeded: 1 });
|
||||
|
||||
expect(sendViaApnsMock).toHaveBeenCalledWith(
|
||||
guardian,
|
||||
expect.objectContaining({
|
||||
recordUserId,
|
||||
recipientUserId: guardian,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user