136 lines
5.7 KiB
TypeScript
136 lines
5.7 KiB
TypeScript
import { describe, expect, it, jest, beforeEach } from "@jest/globals";
|
|
import { createMockLogger } from "../../../helpers/createMockLogger.ts";
|
|
import { makeNotification, makeMessage, makeMessageWithThresholds, makeMessageWithIncident } from "../../../helpers/notificationMessage.ts";
|
|
import { testNotificationProviderContract } from "../../../helpers/notificationProviderContract.ts";
|
|
|
|
const mockGotPost = jest.fn().mockResolvedValue({});
|
|
jest.unstable_mockModule("got", () => ({ default: { post: mockGotPost }, HTTPError: class extends Error {} }));
|
|
|
|
const { SlackProvider } = await import("../../../../src/domain/notifications/providers/slack.ts");
|
|
|
|
const createProvider = () => {
|
|
const logger = createMockLogger();
|
|
return { provider: new SlackProvider(logger as any), logger };
|
|
};
|
|
|
|
testNotificationProviderContract("SlackProvider", {
|
|
create: () => {
|
|
mockGotPost.mockResolvedValue({});
|
|
return createProvider().provider;
|
|
},
|
|
makeNotification: () => makeNotification(),
|
|
});
|
|
|
|
describe("SlackProvider", () => {
|
|
beforeEach(() => mockGotPost.mockReset().mockResolvedValue({}));
|
|
|
|
describe("sendTestAlert", () => {
|
|
it("returns true on success", async () => {
|
|
expect(await createProvider().provider.sendTestAlert(makeNotification())).toBe(true);
|
|
});
|
|
|
|
it("returns false when address is missing", async () => {
|
|
expect(await createProvider().provider.sendTestAlert(makeNotification({ address: "" }))).toBe(false);
|
|
});
|
|
|
|
it("returns false and logs on error", async () => {
|
|
mockGotPost.mockRejectedValue(new Error("fail"));
|
|
const { provider, logger } = createProvider();
|
|
expect(await provider.sendTestAlert(makeNotification())).toBe(false);
|
|
expect(logger.warn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("handles undefined thrown values", async () => {
|
|
mockGotPost.mockRejectedValue(undefined);
|
|
const { provider } = createProvider();
|
|
expect(await provider.sendTestAlert(makeNotification())).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("sendMessage", () => {
|
|
it("sends Block Kit payload and returns true", async () => {
|
|
const { provider } = createProvider();
|
|
expect(await provider.sendMessage(makeNotification() as any, makeMessage())).toBe(true);
|
|
const payload = mockGotPost.mock.calls[0][1].json;
|
|
expect(payload.blocks).toBeDefined();
|
|
expect(payload.attachments).toBeDefined();
|
|
});
|
|
|
|
it("returns false when address is missing", async () => {
|
|
expect(await createProvider().provider.sendMessage(makeNotification({ address: "" }) as any, makeMessage())).toBe(false);
|
|
});
|
|
|
|
it("returns false and logs on error", async () => {
|
|
mockGotPost.mockRejectedValue(new Error("fail"));
|
|
const { provider, logger } = createProvider();
|
|
expect(await provider.sendMessage(makeNotification() as any, makeMessage())).toBe(false);
|
|
expect(logger.warn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("handles undefined thrown values in sendMessage", async () => {
|
|
mockGotPost.mockRejectedValue(undefined);
|
|
const { provider } = createProvider();
|
|
expect(await provider.sendMessage(makeNotification() as any, makeMessage())).toBe(false);
|
|
});
|
|
|
|
it("includes threshold section when thresholds present", async () => {
|
|
const { provider } = createProvider();
|
|
await provider.sendMessage(makeNotification() as any, makeMessageWithThresholds());
|
|
const blocks = mockGotPost.mock.calls[0][1].json.blocks;
|
|
const text = JSON.stringify(blocks);
|
|
expect(text).toContain("Threshold Breaches");
|
|
});
|
|
|
|
it("includes incident button when incident present", async () => {
|
|
const { provider } = createProvider();
|
|
await provider.sendMessage(makeNotification() as any, makeMessageWithIncident());
|
|
const blocks = mockGotPost.mock.calls[0][1].json.blocks;
|
|
expect(blocks.some((b: any) => b.type === "actions")).toBe(true);
|
|
});
|
|
|
|
it("includes details section when details are present", async () => {
|
|
const { provider } = createProvider();
|
|
await provider.sendMessage(makeNotification() as any, makeMessage());
|
|
const blocks = mockGotPost.mock.calls[0][1].json.blocks;
|
|
const text = JSON.stringify(blocks);
|
|
expect(text).toContain("Additional Information");
|
|
});
|
|
|
|
it("links the incident button to the monitor's incidents page", async () => {
|
|
const { provider } = createProvider();
|
|
await provider.sendMessage(makeNotification() as any, makeMessageWithIncident());
|
|
const blocks = mockGotPost.mock.calls[0][1].json.blocks;
|
|
const actions = blocks.find((b: any) => b.type === "actions");
|
|
expect(actions.elements[0].url).toBe("https://app.example.com/incidents/mon-1");
|
|
});
|
|
|
|
it("omits threshold, details, and incident sections when not present", async () => {
|
|
const { provider } = createProvider();
|
|
const msg = makeMessage();
|
|
msg.content.thresholds = undefined;
|
|
msg.content.details = undefined;
|
|
msg.content.incident = undefined;
|
|
await provider.sendMessage(makeNotification() as any, msg);
|
|
const blocks = mockGotPost.mock.calls[0][1].json.blocks;
|
|
const text = JSON.stringify(blocks);
|
|
expect(text).not.toContain("Additional Information");
|
|
expect(blocks.some((b: any) => b.type === "actions")).toBe(false);
|
|
});
|
|
|
|
it("maps all severity levels to colors", async () => {
|
|
const { provider } = createProvider();
|
|
for (const severity of ["critical", "warning", "success", "info"] as const) {
|
|
mockGotPost.mockClear();
|
|
await provider.sendMessage(makeNotification() as any, makeMessage({ severity }));
|
|
expect(mockGotPost.mock.calls[0][1].json.attachments[0].color).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
it("uses default color for unknown severity", async () => {
|
|
const { provider } = createProvider();
|
|
await provider.sendMessage(makeNotification() as any, makeMessage({ severity: "unknown" as any }));
|
|
expect(mockGotPost.mock.calls[0][1].json.attachments[0].color).toBe("#808080");
|
|
});
|
|
});
|
|
});
|