Files
bodyshop/server/notifications/dispatchJobWatcherNotification.test.js

232 lines
6.6 KiB
JavaScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const mock = require("mock-require");
const graphClientModuleId = require.resolve("../graphql-client/graphql-client");
const queriesModuleId = require.resolve("../graphql-client/queries");
const emailQueueModuleId = require.resolve("./queues/emailQueue");
const appQueueModuleId = require.resolve("./queues/appQueue");
const fcmQueueModuleId = require.resolve("./queues/fcmQueue");
const dispatcherModuleId = require.resolve("./dispatchJobWatcherNotification");
const dispatchEmailsToQueueMock = vi.fn();
const dispatchAppsToQueueMock = vi.fn();
const dispatchFcmsToQueueMock = vi.fn();
const loadDispatcher = ({ requestMock }) => {
mock.stopAll();
dispatchEmailsToQueueMock.mockReset();
dispatchAppsToQueueMock.mockReset();
dispatchFcmsToQueueMock.mockReset();
mock(graphClientModuleId, { client: { request: requestMock } });
mock(queriesModuleId, {
GET_JOB_WATCHERS: "GET_JOB_WATCHERS",
GET_NOTIFICATION_ASSOCIATIONS: "GET_NOTIFICATION_ASSOCIATIONS"
});
mock(emailQueueModuleId, { dispatchEmailsToQueue: dispatchEmailsToQueueMock });
mock(appQueueModuleId, { dispatchAppsToQueue: dispatchAppsToQueueMock });
mock(fcmQueueModuleId, { dispatchFcmsToQueue: dispatchFcmsToQueueMock });
delete require.cache[dispatcherModuleId];
return require(dispatcherModuleId);
};
afterEach(() => {
mock.stopAll();
delete require.cache[dispatcherModuleId];
});
describe("dispatchJobWatcherNotification", () => {
it("dispatches queue payloads using watcher settings plus fallback defaults for extra recipients", async () => {
const requestMock = vi.fn(async (query) => {
if (query === "GET_JOB_WATCHERS") {
return {
job_watchers: [
{
user_email: "watcher@example.com",
user: {
employee: {
id: "emp-1",
first_name: "Pat",
last_name: "Lee"
}
}
}
],
job: {
ro_number: "RO-123",
bodyshop: {
id: "shop-1",
shopname: "ImEX",
timezone: "America/Toronto"
}
}
};
}
if (query === "GET_NOTIFICATION_ASSOCIATIONS") {
return {
associations: [
{
id: "assoc-1",
useremail: "watcher@example.com",
notification_settings: {
"esign-document-opened": {
app: true,
email: false,
fcm: true
}
}
},
{
id: "assoc-2",
useremail: "creator@example.com",
notification_settings: {}
}
]
};
}
return {};
});
const { dispatchJobWatcherNotification } = loadDispatcher({ requestMock });
const logger = { log: vi.fn() };
const result = await dispatchJobWatcherNotification({
jobId: "job-1",
scenarioKey: "esign-document-opened",
key: "notifications.job.esignDocumentOpened",
body: '"Repair Authorization" has been opened.',
variables: { documentId: "123" },
extraRecipientEmails: ["creator@example.com"],
defaultChannelPreferences: {
app: true,
email: false,
fcm: false
},
logger
});
expect(result).toBe(true);
expect(requestMock).toHaveBeenCalledTimes(2);
expect(dispatchEmailsToQueueMock).not.toHaveBeenCalled();
expect(dispatchAppsToQueueMock).toHaveBeenCalledTimes(1);
expect(dispatchAppsToQueueMock.mock.calls[0][0]).toEqual({
appsToDispatch: [
expect.objectContaining({
jobId: "job-1",
jobRoNumber: "RO-123",
bodyShopId: "shop-1",
scenarioKey: "esign-document-opened",
key: "notifications.job.esignDocumentOpened",
recipients: [
{
user: "watcher@example.com",
bodyShopId: "shop-1",
employeeId: "emp-1",
associationId: "assoc-1"
},
{
user: "creator@example.com",
bodyShopId: "shop-1",
employeeId: null,
associationId: "assoc-2"
}
]
})
],
logger
});
expect(dispatchFcmsToQueueMock).toHaveBeenCalledTimes(1);
expect(dispatchFcmsToQueueMock.mock.calls[0][0]).toEqual({
fcmsToDispatch: [
expect.objectContaining({
jobId: "job-1",
scenarioKey: "esign-document-opened",
recipients: [
{
user: "watcher@example.com",
bodyShopId: "shop-1",
employeeId: "emp-1",
associationId: "assoc-1"
}
]
})
],
logger
});
});
it("returns false when no recipients have any enabled channels", async () => {
const requestMock = vi.fn(async (query) => {
if (query === "GET_JOB_WATCHERS") {
return {
job_watchers: [
{
user_email: "watcher@example.com",
user: {
employee: {
id: "emp-1",
first_name: "Pat",
last_name: "Lee"
}
}
}
],
job: {
ro_number: "RO-123",
bodyshop: {
id: "shop-1",
shopname: "ImEX",
timezone: "America/Toronto"
}
}
};
}
if (query === "GET_NOTIFICATION_ASSOCIATIONS") {
return {
associations: [
{
id: "assoc-1",
useremail: "watcher@example.com",
notification_settings: {
"esign-document-opened": {
app: false,
email: false,
fcm: false
}
}
}
]
};
}
return {};
});
const { dispatchJobWatcherNotification } = loadDispatcher({ requestMock });
const result = await dispatchJobWatcherNotification({
jobId: "job-1",
scenarioKey: "esign-document-opened",
key: "notifications.job.esignDocumentOpened",
body: '"Repair Authorization" has been opened.',
logger: { log: vi.fn() }
});
expect(result).toBe(false);
expect(dispatchEmailsToQueueMock).not.toHaveBeenCalled();
expect(dispatchAppsToQueueMock).not.toHaveBeenCalled();
expect(dispatchFcmsToQueueMock).not.toHaveBeenCalled();
});
});