fix: align server test suite with current source implementations

## Changes
- teamsProvider.test.ts: fix got mock wiring (use top-level mockPost
  with dynamic import so mock intercepts correctly), fix getTestMessage
  assertion, fix incident URL path
- superSimpleQueueHelper.test.ts: change default import to named import,
  update constructor from object to 16 positional params, rename
  getMonitorJob -> getHeartbeatJob, add all missing dependencies
- monitorService.test.ts: remove stale constructor params (db,
  stringService, papaparse, errorService), add missing params
  (geoChecksRepository, incidentsRepository), fix method names
  (findLatestChecksByMonitorIds -> findLatestByMonitorIds,
  findDateRangeChecksByMonitor -> findByDateRangeAndMonitorId),
  update assertions from checks -> recentChecks
- jest.config.ts: consolidate @/utils path mapping to resolve .ts files
- Extract shared createMockLogger to test/helpers/

Closes #3457
This commit is contained in:
gorkem-bwl committed 2026-04-03 21:56:14 -04:00
1 parent eac470cb68
commit c80720c8c9
5 files changed
+166 -135

No files matched your search

+1 -2
View File
@@ -9,8 +9,7 @@ const config: Config = {
},
moduleNameMapper: {
"^@/validation/(.*)\\.js$": "<rootDir>/src/validation/$1.js",
"^@/utils/(AppError)\\.js$": "<rootDir>/src/utils/$1.ts",
"^@/utils/(.*)\\.js$": "<rootDir>/src/utils/$1.js",
"^@/utils/(.*)\\.js$": "<rootDir>/src/utils/$1.ts",
"^@/(.*)\\.ts$": "<rootDir>/src/$1.ts",
"^@/(.*)\\.js$": "<rootDir>/src/$1.ts",
"^@/(.*)$": "<rootDir>/src/$1",
+8
View File
@@ -0,0 +1,8 @@
import { jest } from "@jest/globals";
export const createMockLogger = () => ({
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
});
+55 -68
View File
@@ -1,6 +1,13 @@
import { jest } from "@jest/globals";
import { MonitorService } from "../src/service/business/monitorService.ts";
import type { IChecksRepository, IMonitorStatsRepository, IMonitorsRepository, IStatusPagesRepository } from "../src/repositories/index.ts";
import type {
IChecksRepository,
IGeoChecksRepository,
IIncidentsRepository,
IMonitorStatsRepository,
IMonitorsRepository,
IStatusPagesRepository,
} from "../src/repositories/index.ts";
const createMonitorsRepositoryMock = () =>
({
@@ -8,16 +15,11 @@ const createMonitorsRepositoryMock = () =>
findByTeamId: jest.fn(),
findById: jest.fn(),
findMonitorsSummaryByTeamId: jest.fn(),
findGroupsByTeamId: jest.fn(),
create: jest.fn(),
createBulkMonitors: jest.fn(),
deleteByTeamId: jest.fn(),
}) as unknown as IMonitorsRepository;
const createChecksRepositoryMock = () =>
({
findLatestChecksByMonitorIds: jest.fn(),
findDateRangeChecksByMonitor: jest.fn(),
findByDateRangeAndMonitorId: jest.fn(),
}) as unknown as IChecksRepository;
const createMonitorStatsRepositoryMock = () =>
@@ -31,82 +33,82 @@ const createStatusPagesRepositoryMock = () =>
removeMonitorFromStatusPages: jest.fn(),
}) as unknown as IStatusPagesRepository;
const createGeoChecksRepositoryMock = () => ({}) as unknown as IGeoChecksRepository;
const createIncidentsRepositoryMock = () => ({}) as unknown as IIncidentsRepository;
const createService = ({
monitorsRepository = createMonitorsRepositoryMock(),
checksRepository = createChecksRepositoryMock(),
monitorStatsRepository = createMonitorStatsRepositoryMock(),
statusPagesRepository = createStatusPagesRepositoryMock(),
geoChecksRepository = createGeoChecksRepositoryMock(),
incidentsRepository = createIncidentsRepositoryMock(),
}: {
monitorsRepository?: IMonitorsRepository;
checksRepository?: IChecksRepository;
monitorStatsRepository?: IMonitorStatsRepository;
statusPagesRepository?: IStatusPagesRepository;
geoChecksRepository?: IGeoChecksRepository;
incidentsRepository?: IIncidentsRepository;
} = {}) => {
return new MonitorService({
db: {
checkModule: { deleteChecks: jest.fn() },
statusPageModule: { deleteStatusPagesByMonitorId: jest.fn() },
pageSpeedCheckModule: { deletePageSpeedChecksByMonitorId: jest.fn() },
notificationModule: { deleteNotificationsByMonitorId: jest.fn() },
},
jobQueue: {
addJob: jest.fn(),
updateJob: jest.fn(),
resumeJob: jest.fn(),
pauseJob: jest.fn(),
deleteJob: jest.fn(),
},
stringService: {},
emailService: { buildEmail: jest.fn(), sendEmail: jest.fn() },
papaparse: { parse: jest.fn(), unparse: jest.fn() },
logger: { info: jest.fn(), error: jest.fn(), warn: jest.fn() },
errorService: {
createAuthorizationError: jest.fn(() => new Error("unauthorized")),
createServerError: jest.fn(() => new Error("server")),
createBadRequestError: jest.fn(() => new Error("bad request")),
createNotFoundError: jest.fn(() => new Error("not found")),
},
} as any,
emailService: { buildEmail: jest.fn(), sendEmail: jest.fn() } as any,
logger: { info: jest.fn(), error: jest.fn(), warn: jest.fn() } as any,
games: [],
monitorsRepository,
checksRepository,
geoChecksRepository,
monitorStatsRepository,
statusPagesRepository,
incidentsRepository,
});
};
describe("MonitorService", () => {
describe("getMonitorsWithChecksByTeamId", () => {
it("returns monitors enriched with normalized checks", async () => {
it("returns monitors enriched with normalized recentChecks", async () => {
const monitorsRepository = createMonitorsRepositoryMock();
(monitorsRepository.findMonitorCountByTeamIdAndType as jest.Mock).mockResolvedValue(2);
(monitorsRepository.findMonitorsSummaryByTeamId as jest.Mock).mockResolvedValue({
totalMonitors: 2,
upMonitors: 2,
downMonitors: 0,
pausedMonitors: 0,
});
(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([
{ id: "m1", name: "Monitor 1", interval: 60000 },
{ id: "m2", name: "Monitor 2", interval: 60000 },
{
id: "m1",
name: "Monitor 1",
type: "http",
interval: 60000,
recentChecks: [
{ responseTime: 10, status: true, message: "OK" },
{ responseTime: 20, status: true, message: "OK" },
],
},
{
id: "m2",
name: "Monitor 2",
type: "http",
interval: 60000,
recentChecks: [{ responseTime: 50, status: true, message: "OK" }],
},
]);
const checksRepository = createChecksRepositoryMock();
(checksRepository.findLatestChecksByMonitorIds as jest.Mock).mockResolvedValue({
m1: [
{ responseTime: 10, status: true, message: "OK" },
{ responseTime: 20, status: true, message: "OK" },
],
m2: [{ responseTime: 50, status: true, message: "OK" }],
});
const service = createService({ monitorsRepository, checksRepository });
const service = createService({ monitorsRepository });
const result = await service.getMonitorsWithChecksByTeamId({ teamId: "team" });
expect(result).toMatchObject({ count: 2 });
expect(result.monitors).toHaveLength(2);
expect(result.monitors[0]).toHaveProperty("checks");
expect(result.monitors[0].checks.length).toBeGreaterThan(0);
expect(result.monitors[0].checks[0]).toEqual(
expect.objectContaining({
responseTime: expect.any(Number),
status: expect.any(Boolean),
message: expect.any(String),
})
);
expect(result.monitors[0]).toHaveProperty("recentChecks");
});
});
@@ -120,15 +122,15 @@ describe("MonitorService", () => {
const service = createService({ monitorsRepository });
const result = await service.getMonitorsByTeamId({ teamId: "team" } as any);
expect(result).toHaveLength(2);
expect(result[0]).toHaveProperty("id", "m1");
expect(result![0]).toHaveProperty("id", "m1");
});
});
describe("getMonitorsWithChecksByTeamId summary", () => {
it("includes summary and monitors with checks", async () => {
it("includes summary and monitors with recentChecks", async () => {
const monitorsRepository = createMonitorsRepositoryMock();
(monitorsRepository.findMonitorCountByTeamIdAndType as jest.Mock).mockResolvedValue(1);
(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([{ id: "m1", type: "http" }]);
(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([{ id: "m1", type: "http", recentChecks: [] }]);
(monitorsRepository.findMonitorsSummaryByTeamId as jest.Mock).mockResolvedValue({
totalMonitors: 1,
upMonitors: 1,
@@ -136,15 +138,12 @@ describe("MonitorService", () => {
pausedMonitors: 0,
});
const checksRepository = createChecksRepositoryMock();
(checksRepository.findLatestChecksByMonitorIds as jest.Mock).mockResolvedValue({ m1: [] });
const service = createService({ monitorsRepository, checksRepository });
const service = createService({ monitorsRepository });
const result = await service.getMonitorsWithChecksByTeamId({ teamId: "team" });
expect(result).toEqual({
summary: { totalMonitors: 1, upMonitors: 1, downMonitors: 0, pausedMonitors: 0 },
count: 1,
monitors: [{ id: "m1", type: "http", checks: [] }],
monitors: [{ id: "m1", type: "http", recentChecks: [] }],
});
});
});
@@ -155,23 +154,11 @@ describe("MonitorService", () => {
const monitor = {
id: "monitor-1",
teamId: TEAM_ID,
name: "Hardware monitor",
name: "HTTP monitor",
interval: 60000,
statusWindow: [],
statusWindowSize: 5,
statusWindowThreshold: 60,
type: "http",
ignoreTlsErrors: false,
url: "https://example.com",
isActive: true,
alertThreshold: 5,
cpuAlertThreshold: 5,
memoryAlertThreshold: 5,
diskAlertThreshold: 5,
tempAlertThreshold: 5,
selectedDisks: [],
notifications: [],
group: null,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
@@ -179,7 +166,7 @@ describe("MonitorService", () => {
const monitorsRepository = createMonitorsRepositoryMock();
(monitorsRepository.findById as jest.Mock).mockResolvedValue(monitor);
const checksRepository = createChecksRepositoryMock();
(checksRepository.findDateRangeChecksByMonitor as jest.Mock).mockResolvedValue({
(checksRepository.findByDateRangeAndMonitorId as jest.Mock).mockResolvedValue({
monitorType: "http",
groupedChecks: [{ _id: "2024-01-01", avgResponseTime: 100, totalChecks: 2 }],
groupedUpChecks: [{ _id: "2024-01-01", totalChecks: 2, avgResponseTime: 90 }],
+74 -22
View File
@@ -1,36 +1,89 @@
import { describe, expect, it, jest } from "@jest/globals";
import SuperSimpleQueueHelper from "../src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts";
import { SuperSimpleQueueHelper } from "../src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts";
import type { Monitor } from "../src/types/monitor.ts";
import { createMockLogger } from "./helpers/createMockLogger.ts";
const createLogger = () => ({ info: jest.fn(), error: jest.fn(), warn: jest.fn(), debug: jest.fn() });
const createHelper = (overrides?: Partial<ConstructorParameters<typeof SuperSimpleQueueHelper>[0]>) => {
const createHelper = (overrides?: Record<string, unknown>) => {
const maintenanceWindowsRepository = {
findByMonitorId: jest.fn().mockResolvedValue([]),
};
const statusServiceMock = {
updateMonitorStatus: jest.fn().mockResolvedValue({ monitor: { id: "m1" }, statusChanged: true, prevStatus: false }),
const monitorsRepository = {
updateById: jest.fn().mockResolvedValue({}),
findAllMonitorIds: jest.fn().mockResolvedValue(["m1"]),
deleteByTeamIdsNotIn: jest.fn().mockResolvedValue(0),
};
const helper = new SuperSimpleQueueHelper({
logger: createLogger(),
const teamsRepository = {
findAllTeamIds: jest.fn().mockResolvedValue(["team"]),
};
const monitorStatsRepository = {
deleteByMonitorIdsNotIn: jest.fn().mockResolvedValue(0),
};
const checksRepository = {
deleteByMonitorIdsNotIn: jest.fn().mockResolvedValue(0),
};
const incidentsRepository = {
deleteByMonitorIdsNotIn: jest.fn().mockResolvedValue(0),
};
const geoChecksRepository = {
deleteByMonitorIdsNotIn: jest.fn().mockResolvedValue(0),
};
const statusServiceMock = {
updateMonitorStatus: jest.fn().mockResolvedValue({ monitor: { id: "m1", status: "up" }, statusChanged: false, prevStatus: "up", code: 200 }),
};
const settingsServiceMock = {
getDBSettings: jest.fn().mockResolvedValue({ checkTTL: 30 }),
};
const geoChecksServiceMock = {
buildGeoCheck: jest.fn().mockResolvedValue(null),
};
const defaults = {
logger: createMockLogger(),
networkService: { requestStatus: jest.fn() },
statusService: statusServiceMock,
notificationsService: { handleNotifications: jest.fn().mockResolvedValue(undefined) },
checkService: { buildCheck: jest.fn().mockResolvedValue({}) },
buffer: { addToBuffer: jest.fn() },
checkService: { buildCheck: jest.fn().mockReturnValue({}), deleteOlderThan: jest.fn().mockResolvedValue(0) },
settingsService: settingsServiceMock,
buffer: { addToBuffer: jest.fn(), addGeoCheckToBuffer: jest.fn() },
incidentService: { handleIncident: jest.fn().mockResolvedValue(undefined) },
maintenanceWindowsRepository,
monitorsRepository,
teamsRepository,
monitorStatsRepository,
checksRepository,
incidentsRepository,
geoChecksService: geoChecksServiceMock,
geoChecksRepository,
...overrides,
});
return { helper, maintenanceWindowsRepository };
};
const helper = new SuperSimpleQueueHelper(
defaults.logger as any,
defaults.networkService as any,
defaults.statusService as any,
defaults.notificationsService as any,
defaults.checkService as any,
defaults.settingsService as any,
defaults.buffer as any,
defaults.incidentService as any,
defaults.maintenanceWindowsRepository as any,
defaults.monitorsRepository as any,
defaults.teamsRepository as any,
defaults.monitorStatsRepository as any,
defaults.checksRepository as any,
defaults.incidentsRepository as any,
defaults.geoChecksService as any,
defaults.geoChecksRepository as any
);
return { helper, maintenanceWindowsRepository, defaults };
};
describe("SuperSimpleQueueHelper", () => {
describe("getMonitorJob", () => {
describe("getHeartbeatJob", () => {
it("skips execution when monitor is in maintenance window", async () => {
const { helper } = createHelper();
const spy = jest.spyOn(helper, "isInMaintenanceWindow").mockResolvedValue(true);
const job = helper.getMonitorJob();
const job = helper.getHeartbeatJob();
await job({ id: "m1", teamId: "team", interval: 60000 } as Monitor);
expect(helper["networkService"].requestStatus).not.toHaveBeenCalled();
expect(helper["logger"].debug).toHaveBeenCalledWith(
@@ -40,17 +93,16 @@ describe("SuperSimpleQueueHelper", () => {
});
it("processes monitor status and notifications when active", async () => {
const networkResponse = { monitor: { id: "m1" }, status: true };
const updatedMonitor = { id: "m1", status: true };
const networkResponse = { monitor: { id: "m1" }, status: true, code: 200, message: "OK" };
const statusServiceMock = {
updateMonitorStatus: jest.fn().mockResolvedValue({ monitor: { id: "m1", status: "up" }, statusChanged: false, prevStatus: "up", code: 200 }),
};
const { helper } = createHelper({
networkService: { requestStatus: jest.fn().mockResolvedValue(networkResponse) },
statusService: {
updateMonitorStatus: jest.fn().mockResolvedValue({ monitor: updatedMonitor, statusChanged: true, prevStatus: false, code: 200 }),
},
notificationsService: { handleNotifications: jest.fn().mockResolvedValue(undefined) },
statusService: statusServiceMock,
});
jest.spyOn(helper, "isInMaintenanceWindow").mockResolvedValue(false);
const job = helper.getMonitorJob();
const job = helper.getHeartbeatJob();
const monitor = { id: "m1", teamId: "team" } as Monitor;
await job(monitor);
expect(helper["networkService"].requestStatus).toHaveBeenCalledWith(monitor);
@@ -58,7 +110,7 @@ describe("SuperSimpleQueueHelper", () => {
it("throws when monitor id is missing", async () => {
const { helper } = createHelper();
const job = helper.getMonitorJob();
const job = helper.getHeartbeatJob();
await expect(job({} as Monitor)).rejects.toThrow("No monitor id");
expect(helper["logger"].warn).toHaveBeenCalled();
});
+28 -43
View File
@@ -1,19 +1,15 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals";
import { TeamsProvider } from "../src/service/infrastructure/notificationProviders/teams.ts";
import type { Notification } from "../src/types/notification.ts";
import type { NotificationMessage } from "../src/types/notificationMessage.ts";
import { createMockLogger } from "./helpers/createMockLogger.ts";
// Mock got
const mockPost = jest.fn();
jest.unstable_mockModule("got", () => ({
default: { post: jest.fn() },
default: { post: mockPost },
HTTPError: class HTTPError extends Error {},
}));
const createLogger = () => ({
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
});
const { TeamsProvider } = await import("../src/service/infrastructure/notificationProviders/teams.ts");
const createNotification = (overrides?: Partial<Notification>): Notification => ({
id: "notif-1",
@@ -58,17 +54,14 @@ const createMessage = (overrides?: Partial<NotificationMessage>): NotificationMe
});
describe("TeamsProvider", () => {
let provider: TeamsProvider;
let logger: ReturnType<typeof createLogger>;
let gotPost: jest.Mock;
let provider: InstanceType<typeof TeamsProvider>;
let logger: ReturnType<typeof createMockLogger>;
beforeEach(async () => {
logger = createLogger();
beforeEach(() => {
logger = createMockLogger();
provider = new TeamsProvider(logger);
const got = await import("got");
gotPost = got.default.post as jest.Mock;
gotPost.mockReset();
gotPost.mockResolvedValue({});
mockPost.mockReset();
mockPost.mockResolvedValue({});
});
describe("sendTestAlert", () => {
@@ -76,35 +69,33 @@ describe("TeamsProvider", () => {
const notification = createNotification({ address: undefined });
const result = await provider.sendTestAlert(notification);
expect(result).toBe(false);
expect(gotPost).not.toHaveBeenCalled();
expect(mockPost).not.toHaveBeenCalled();
});
it("sends an Adaptive Card test message and returns true on success", async () => {
const notification = createNotification();
const result = await provider.sendTestAlert(notification);
expect(result).toBe(true);
expect(gotPost).toHaveBeenCalledTimes(1);
expect(mockPost).toHaveBeenCalledTimes(1);
const [url, options] = gotPost.mock.calls[0] as [string, { json: any; headers: any }];
const [url, options] = mockPost.mock.calls[0] as [string, { json: any; headers: any }];
expect(url).toBe(notification.address);
expect(options.headers["Content-Type"]).toBe("application/json");
// Verify Teams webhook envelope
const payload = options.json;
expect(payload.type).toBe("message");
expect(payload.attachments).toHaveLength(1);
expect(payload.attachments[0].contentType).toBe("application/vnd.microsoft.card.adaptive");
// Verify Adaptive Card structure
const card = payload.attachments[0].content;
expect(card.type).toBe("AdaptiveCard");
expect(card.version).toBe("1.4");
expect(card.body[0].type).toBe("TextBlock");
expect(card.body[0].text).toContain("test notification");
expect(card.body[0].text).toBe("This is a test notification from Checkmate");
});
it("returns false and logs warning on HTTP error", async () => {
gotPost.mockRejectedValue(new Error("Network error"));
mockPost.mockRejectedValue(new Error("Network error"));
const notification = createNotification();
const result = await provider.sendTestAlert(notification);
expect(result).toBe(false);
@@ -122,7 +113,7 @@ describe("TeamsProvider", () => {
const notification = createNotification({ address: undefined });
const result = await provider.sendMessage(notification, createMessage());
expect(result).toBe(false);
expect(gotPost).not.toHaveBeenCalled();
expect(mockPost).not.toHaveBeenCalled();
});
it("sends a well-formed Adaptive Card and returns true", async () => {
@@ -131,9 +122,9 @@ describe("TeamsProvider", () => {
const result = await provider.sendMessage(notification, message);
expect(result).toBe(true);
expect(gotPost).toHaveBeenCalledTimes(1);
expect(mockPost).toHaveBeenCalledTimes(1);
const [url, options] = gotPost.mock.calls[0] as [string, { json: any }];
const [url, options] = mockPost.mock.calls[0] as [string, { json: any }];
expect(url).toBe(notification.address);
const payload = options.json;
@@ -143,18 +134,13 @@ describe("TeamsProvider", () => {
expect(card.type).toBe("AdaptiveCard");
expect(card.version).toBe("1.4");
// Verify body contains expected elements
const textBlocks = card.body.filter((b: any) => b.type === "TextBlock");
const factSets = card.body.filter((b: any) => b.type === "FactSet");
// Title block
expect(textBlocks[0].text).toBe(message.content.title);
expect(textBlocks[0].color).toBe("attention"); // critical -> attention
// Summary block
expect(textBlocks[0].color).toBe("attention");
expect(textBlocks[1].text).toBe(message.content.summary);
// FactSet with monitor details
expect(factSets).toHaveLength(1);
const facts = factSets[0].facts;
expect(facts).toEqual(
@@ -165,11 +151,10 @@ describe("TeamsProvider", () => {
])
);
// Incident action button
expect(card.actions).toHaveLength(1);
expect(card.actions[0].type).toBe("Action.OpenUrl");
expect(card.actions[0].title).toBe("View Incident");
expect(card.actions[0].url).toContain("/infrastructure/mon-1");
expect(card.actions[0].url).toContain("/incidents/inc-1");
});
it("omits actions when no incident is present", async () => {
@@ -184,7 +169,7 @@ describe("TeamsProvider", () => {
const result = await provider.sendMessage(notification, message);
expect(result).toBe(true);
const [, options] = gotPost.mock.calls[0] as [string, { json: any }];
const [, options] = mockPost.mock.calls[0] as [string, { json: any }];
const card = options.json.attachments[0].content;
expect(card.actions).toBeUndefined();
});
@@ -212,7 +197,7 @@ describe("TeamsProvider", () => {
await provider.sendMessage(notification, message);
const [, options] = gotPost.mock.calls[0] as [string, { json: any }];
const [, options] = mockPost.mock.calls[0] as [string, { json: any }];
const card = options.json.attachments[0].content;
// Title should use "warning" color
@@ -222,7 +207,7 @@ describe("TeamsProvider", () => {
const thresholdHeader = card.body.find((b: any) => b.type === "TextBlock" && b.text === "**Threshold Breaches**");
expect(thresholdHeader).toBeDefined();
const cpuBlock = card.body.find((b: any) => b.type === "TextBlock" && b.text?.includes("CPU"));
const cpuBlock = card.body.find((b: any) => b.type === "TextBlock" && b.text?.includes("**CPU**"));
expect(cpuBlock).toBeDefined();
expect(cpuBlock.text).toContain("95%");
expect(cpuBlock.text).toContain("threshold: 80%");
@@ -239,20 +224,20 @@ describe("TeamsProvider", () => {
] as const;
for (const { severity, expected } of severityMap) {
gotPost.mockReset();
gotPost.mockResolvedValue({});
mockPost.mockReset();
mockPost.mockResolvedValue({});
const message = createMessage({ severity });
await provider.sendMessage(notification, message);
const [, options] = gotPost.mock.calls[0] as [string, { json: any }];
const [, options] = mockPost.mock.calls[0] as [string, { json: any }];
const card = options.json.attachments[0].content;
expect(card.body[0].color).toBe(expected);
}
});
it("returns false and logs warning on HTTP error", async () => {
gotPost.mockRejectedValue(new Error("502 Bad Gateway"));
mockPost.mockRejectedValue(new Error("502 Bad Gateway"));
const notification = createNotification();
const result = await provider.sendMessage(notification, createMessage());
expect(result).toBe(false);