diff --git a/config/jest-backend.config.js b/config/jest-backend.config.js index 1a88d9a..db39512 100644 --- a/config/jest-backend.config.js +++ b/config/jest-backend.config.js @@ -1,5 +1,5 @@ module.exports = { "rootDir": "..", - "testRegex": "./test/backend.spec.js", + "testRegex": ["./test/backend.spec.js", "./server/.*.spec.js"], }; diff --git a/server/notification-providers/aliyun-sms.js b/server/notification-providers/aliyun-sms.js index 6a20632..952efec 100644 --- a/server/notification-providers/aliyun-sms.js +++ b/server/notification-providers/aliyun-sms.js @@ -8,7 +8,6 @@ class AliyunSMS extends NotificationProvider { name = "AliyunSMS"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (heartbeatJSON != null) { @@ -18,8 +17,9 @@ class AliyunSMS extends NotificationProvider { status: this.statusToString(heartbeatJSON["status"]), msg: heartbeatJSON["msg"], }); - if (this.sendSms(notification, msgBody)) { - return okMsg; + if (await this.sendSms(notification, msgBody)) { + return this.sendSuccess; + //TODO account for cases where sendSMS returns false. } } else { let msgBody = JSON.stringify({ @@ -28,8 +28,8 @@ class AliyunSMS extends NotificationProvider { status: "", msg: msg, }); - if (this.sendSms(notification, msgBody)) { - return okMsg; + if (await this.sendSms(notification, msgBody)) { + return this.sendSuccess; } } } catch (error) { @@ -48,7 +48,7 @@ class AliyunSMS extends NotificationProvider { SignatureMethod: "HMAC-SHA1", SignatureVersion: "1.0", SignatureNonce: Math.random().toString(), - Timestamp: new Date().toISOString(), + Timestamp: new Date(Date.now()).toISOString(), Action: "SendSms", Version: "2017-05-25", }; diff --git a/server/notification-providers/aliyun-sms.spec.js b/server/notification-providers/aliyun-sms.spec.js new file mode 100644 index 0000000..c58a765 --- /dev/null +++ b/server/notification-providers/aliyun-sms.spec.js @@ -0,0 +1,243 @@ +jest.mock("axios"); + +const axios = require("axios"); + +const { UP } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const AliyunSMS = require("./aliyun-sms"); + +beforeEach(() => { + axios.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new AliyunSMS(); + expect(notification.name).toBe("AliyunSMS"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementation(() => + new Date("2019-05-14T11:01:58.135Z") + ); + + jest.spyOn(global.Math, "random") + .mockImplementation(() => + 0.0000111010100 + ); + + let response = { + data: { + Message: "OK" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new AliyunSMS(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios).toHaveBeenCalledWith({ + data: "TemplateParam=%7B%22name%22%3A%22testing%22%2C%22time%22%3A%22example%20time%22%2C%22status%22%3A%22UP%22%2C%22msg%22%3A%22some%20message%22%7D&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&SignatureNonce=0.00001110101&Timestamp=2019-05-14T11%3A01%3A58.135Z&Action=SendSms&Version=2017-05-25&Signature=73QTXvIaPHJIEo%2BCV1bzaZ5rzh4%3D", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + url: "http://dysmsapi.aliyuncs.com/", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementation(() => + new Date("2019-05-14T11:01:58.135Z") + ); + + jest.spyOn(global.Math, "random") + .mockImplementation(() => + 0.0000111010100 + ); + + let response = { + data: { + Message: "OK" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new AliyunSMS(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios).toHaveBeenCalledWith({ + data: "TemplateParam=%7B%22name%22%3A%22%22%2C%22time%22%3A%22%22%2C%22status%22%3A%22%22%2C%22msg%22%3A%22PassedInMessage%22%7D&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&SignatureNonce=0.00001110101&Timestamp=2019-05-14T11%3A01%3A58.135Z&Action=SendSms&Version=2017-05-25&Signature=bXj4C8u60n6Xfiqf3VhtyqtW6Fk%3D", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + url: "http://dysmsapi.aliyuncs.com/", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementation(() => + new Date("2019-05-14T11:01:58.135Z") + ); + + jest.spyOn(global.Math, "random") + .mockImplementation(() => + 0.0000111010100 + ); + + let response = { + data: { + Message: "OK" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new AliyunSMS(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios).toHaveBeenCalledWith({ + data: "TemplateParam=%7B%22name%22%3A%22%22%2C%22time%22%3A%22%22%2C%22status%22%3A%22%22%2C%22msg%22%3A%22PassedInMessage%22%7D&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&SignatureNonce=0.00001110101&Timestamp=2019-05-14T11%3A01%3A58.135Z&Action=SendSms&Version=2017-05-25&Signature=bXj4C8u60n6Xfiqf3VhtyqtW6Fk%3D", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + url: "http://dysmsapi.aliyuncs.com/", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + jest.spyOn(global.Date, "now") + .mockImplementation(() => + new Date("2019-05-14T11:01:58.135Z") + ); + + jest.spyOn(global.Math, "random") + .mockImplementation(() => + 0.0000111010100 + ); + + axios.mockImplementation(() => { + throw new Error("Test Error"); + }); + + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let notif = new AliyunSMS(); + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + //axios general error on catching another error is not the cleanest, but works. + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios).toHaveBeenCalledWith({ + data: "TemplateParam=%7B%22name%22%3A%22%22%2C%22time%22%3A%22%22%2C%22status%22%3A%22%22%2C%22msg%22%3A%22PassedInMessage%22%7D&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&SignatureNonce=0.00001110101&Timestamp=2019-05-14T11%3A01%3A58.135Z&Action=SendSms&Version=2017-05-25&Signature=bXj4C8u60n6Xfiqf3VhtyqtW6Fk%3D", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + url: "http://dysmsapi.aliyuncs.com/", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call sendMail with proper data", async () => { + jest.spyOn(global.Date, "now") + .mockImplementation(() => + new Date("2019-05-14T11:01:58.135Z") + ); + + jest.spyOn(global.Math, "random") + .mockImplementation(() => + 0.0000111010100 + ); + + let response = { + data: { + Message: "OK" + } + }; + axios.mockResolvedValueOnce(response); + let notificationConf = { + type: "AliyunSMS", + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios).toHaveBeenCalledWith({ + data: "TemplateParam=%7B%22name%22%3A%22testing%22%2C%22time%22%3A%22example%20time%22%2C%22status%22%3A%22UP%22%2C%22msg%22%3A%22some%20message%22%7D&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&SignatureNonce=0.00001110101&Timestamp=2019-05-14T11%3A01%3A58.135Z&Action=SendSms&Version=2017-05-25&Signature=73QTXvIaPHJIEo%2BCV1bzaZ5rzh4%3D", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + url: "http://dysmsapi.aliyuncs.com/", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/apprise.js b/server/notification-providers/apprise.js index fdcd8d6..90cefac 100644 --- a/server/notification-providers/apprise.js +++ b/server/notification-providers/apprise.js @@ -1,22 +1,22 @@ const NotificationProvider = require("./notification-provider"); -const child_process = require("child_process"); +const childProcess = require("child_process"); class Apprise extends NotificationProvider { name = "apprise"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]) + let s = childProcess.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]); let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found"; if (output) { if (! output.includes("ERROR")) { - return "Sent Successfully"; + return this.sendSuccess; } - throw new Error(output) + throw new Error(output); } else { return "No output from apprise"; } diff --git a/server/notification-providers/apprise.spec.js b/server/notification-providers/apprise.spec.js new file mode 100644 index 0000000..148521a --- /dev/null +++ b/server/notification-providers/apprise.spec.js @@ -0,0 +1,112 @@ +jest.mock("child_process", () => ({ + spawnSync: jest.fn(), +})); + +const childProcess = require("child_process"); +const { UP } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Apprise = require("./apprise"); + +beforeEach(() => { + childProcess.spawnSync.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Apprise(); + expect(notification.name).toBe("apprise"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call apprise with the proper default data", async () => { + + childProcess.spawnSync.mockImplementationOnce(() => { + return { stdout: "response" }; + }); + + let notif = new Apprise(); + let notificationConf = { + appriseURL: "appriseURL", + }; + let msg = "PassedInMessage"; + let res = await notif.send(notificationConf, msg, null, null); + + expect(childProcess.spawnSync).toHaveBeenCalledWith("apprise", ["-vv", "-b", "PassedInMessage", "appriseURL"]); + expect(res).toBe("Sent Successfully."); + }); + + //TODO code under test unreachable. Remove or resolve. + // it("should call output no data when no data", async () => { + + // childProcess.spawnSync.mockImplementationOnce(() => { + // return { stdout: "" }; + // }); + + // let notif = new Apprise(); + // let notificationConf = { + // appriseURL: "appriseURL", + // }; + // let msg = "PassedInMessage"; + // let res = await notif.send(notificationConf, msg, null, null); + + // expect(childProcess.spawnSync).toHaveBeenCalledWith("apprise", ["-vv", "-b", "PassedInMessage", "appriseURL"]); + // expect(res).toBe("No output from apprise"); + // }); + +}); + +describe("notification to act properly on errors from apprise", () => { + it("should call apprise with the proper default data", async () => { + + childProcess.spawnSync.mockImplementationOnce(() => { + return { stdout: "ERROR FROM APPRISE" }; + }); + + let notif = new Apprise(); + let notificationConf = { + appriseURL: "appriseURL", + }; + let msg = "PassedInMessage"; + try { + await notif.send(notificationConf, msg, null, null); + expect("not reached").toBe(false); + } catch (e) { + expect(e.message).toBe("ERROR FROM APPRISE"); + } + + expect(childProcess.spawnSync).toHaveBeenCalledWith("apprise", ["-vv", "-b", "PassedInMessage", "appriseURL"]); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call sendMail with proper data", async () => { + childProcess.spawnSync.mockImplementationOnce(() => { + return { stdout: "response" }; + }); + + let notificationConf = { + type: "apprise", + appriseURL: "appriseURL", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + + expect(res).toBe("Sent Successfully."); + + expect(childProcess.spawnSync).toHaveBeenCalledWith("apprise", ["-vv", "-b", "PassedInMessage", "appriseURL"]); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/dingding.js b/server/notification-providers/dingding.js index f099192..db52b0a 100644 --- a/server/notification-providers/dingding.js +++ b/server/notification-providers/dingding.js @@ -7,7 +7,6 @@ class DingDing extends NotificationProvider { name = "DingDing"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (heartbeatJSON != null) { @@ -15,11 +14,11 @@ class DingDing extends NotificationProvider { msgtype: "markdown", markdown: { title: monitorJSON["name"], - text: `## [${this.statusToString(heartbeatJSON["status"])}] \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`, + text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}\n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`, } }; - if (this.sendToDingDing(notification, params)) { - return okMsg; + if (await this.sendToDingDing(notification, params)) { + return this.sendSuccess; } } else { let params = { @@ -28,8 +27,8 @@ class DingDing extends NotificationProvider { content: msg } }; - if (this.sendToDingDing(notification, params)) { - return okMsg; + if (await this.sendToDingDing(notification, params)) { + return this.sendSuccess; } } } catch (error) { diff --git a/server/notification-providers/dingding.spec.js b/server/notification-providers/dingding.spec.js new file mode 100644 index 0000000..b6307ac --- /dev/null +++ b/server/notification-providers/dingding.spec.js @@ -0,0 +1,208 @@ +jest.mock("axios"); + +const { UP } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const DingDing = require("./dingding"); + +const axios = require("axios"); + +beforeEach(() => { + axios.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new DingDing(); + expect(notification.name).toBe("DingDing"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementationOnce(() => + new Date("2019-05-14T11:01:58.135Z").valueOf() + ); + + let response = { + data: { + errmsg: "ok" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new DingDing(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios).toHaveBeenCalledWith({ + data: "{\"msgtype\":\"markdown\",\"markdown\":{\"title\":\"testing\",\"text\":\"## [UP] testing\\n > some message \\n > Time(UTC):example time\"}}", + headers: { + "Content-Type": "application/json", + }, + method: "POST", + url: "https://example.com/webhook×tamp=1557831718135&sign=lCTIn3sYpAYFAw3B2LeTLr7BvcOMAcmZu%2F6rb7kC8Io%3D", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when missing heartbeat", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementationOnce(() => + new Date("2019-05-14T11:01:58.135Z").valueOf() + ); + + let response = { + data: { + errmsg: "ok" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new DingDing(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let res = await notif.send(notificationConf, msg, monitorConf, null); + + expect(axios).toHaveBeenCalledWith({ + data: "{\"msgtype\":\"text\",\"text\":{\"content\":\"PassedInMessage\"}}", + headers: { + "Content-Type": "application/json", + }, + method: "POST", + url: "https://example.com/webhook×tamp=1557831718135&sign=lCTIn3sYpAYFAw3B2LeTLr7BvcOMAcmZu%2F6rb7kC8Io%3D", + }); + expect(res).toBe("Sent Successfully."); + }); + + //TODO need to get correct response when sendToDingDing fails, but no axios error. + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementationOnce(() => + new Date("2019-05-14T11:01:58.135Z").valueOf() + ); + + axios.mockImplementationOnce(() => { + throw new Error("Test Error"); + }); + + let notif = new DingDing(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + try { + await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + console.log("fail"); + expect("Error thrown").toBe(false); + } catch (e) { + //axios general error on catching another error is not the cleanest, but works. + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios).toHaveBeenCalledWith({ + data: "{\"msgtype\":\"markdown\",\"markdown\":{\"title\":\"testing\",\"text\":\"## [UP] testing\\n > some message \\n > Time(UTC):example time\"}}", + headers: { + "Content-Type": "application/json", + }, + method: "POST", + url: "https://example.com/webhook×tamp=1557831718135&sign=lCTIn3sYpAYFAw3B2LeTLr7BvcOMAcmZu%2F6rb7kC8Io%3D", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call sendMail with proper data", async () => { + jest.spyOn(global.Date, "now") + .mockImplementationOnce(() => + new Date("2019-05-14T11:01:58.135Z").valueOf() + ); + + let response = { + data: { + errmsg: "ok" + } + }; + axios.mockResolvedValueOnce(response); + + let notif = new DingDing(); + let notificationConf = { + type: "DingDing", + appriseURL: "appriseURL", + secretKey: "abc", + webHookUrl: "https://example.com/webhook", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + + expect(res).toBe("Sent Successfully."); + + expect(axios).toHaveBeenCalledWith({ + data: "{\"msgtype\":\"markdown\",\"markdown\":{\"title\":\"testing\",\"text\":\"## [UP] testing\\n > some message \\n > Time(UTC):example time\"}}", + headers: { + "Content-Type": "application/json", + }, + method: "POST", + url: "https://example.com/webhook×tamp=1557831718135&sign=lCTIn3sYpAYFAw3B2LeTLr7BvcOMAcmZu%2F6rb7kC8Io%3D", + + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/discord.js b/server/notification-providers/discord.js index 881ad21..06b0273 100644 --- a/server/notification-providers/discord.js +++ b/server/notification-providers/discord.js @@ -7,7 +7,6 @@ class Discord extends NotificationProvider { name = "discord"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { const discordDisplayName = notification.discordUsername || "Uptime Kuma"; @@ -17,9 +16,9 @@ class Discord extends NotificationProvider { let discordtestdata = { username: discordDisplayName, content: msg, - } - await axios.post(notification.discordWebhookUrl, discordtestdata) - return okMsg; + }; + await axios.post(notification.discordWebhookUrl, discordtestdata); + return this.sendSuccess; } let url; @@ -49,7 +48,7 @@ class Discord extends NotificationProvider { }, { name: "Service URL", - value: url, + value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url, }, { name: "Time (UTC)", @@ -61,14 +60,14 @@ class Discord extends NotificationProvider { }, ], }], - } + }; if (notification.discordPrefixMessage) { discorddowndata.content = notification.discordPrefixMessage; } - await axios.post(notification.discordWebhookUrl, discorddowndata) - return okMsg; + await axios.post(notification.discordWebhookUrl, discorddowndata); + return this.sendSuccess; } else if (heartbeatJSON["status"] == UP) { let discordupdata = { @@ -96,17 +95,17 @@ class Discord extends NotificationProvider { }, ], }], - } + }; if (notification.discordPrefixMessage) { discordupdata.content = notification.discordPrefixMessage; } - await axios.post(notification.discordWebhookUrl, discordupdata) - return okMsg; + await axios.post(notification.discordWebhookUrl, discordupdata); + return this.sendSuccess; } } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/discord.spec.js b/server/notification-providers/discord.spec.js new file mode 100644 index 0000000..1583005 --- /dev/null +++ b/server/notification-providers/discord.spec.js @@ -0,0 +1,260 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Discord = require("./discord"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Discord(); + expect(notification.name).toBe("discord"); + }); +}); + +describe("notification to act properly on send", () => { + + it("should call axios with the proper data when missing heartbeat/monitor", async () => { + + let response = {}; + axios.post.mockResolvedValueOnce(response); + + let notif = new Discord(); + let url = "https://example.com/webhook"; + let notificationConf = { + discordUsername: "username", + discordWebhookUrl: url, + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith(url, { + content: "PassedInMessage", + username: "username" + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when having heartbeat & monitor & service up", async () => { + + jest.spyOn(global.Date, "now") + .mockImplementationOnce(() => + new Date("2019-05-14T11:01:58.135Z").valueOf() + ); + + let response = {}; + axios.post.mockResolvedValueOnce(response); + + let notif = new Discord(); + let url = "https://example.com/webhook"; + let notificationConf = { + discordUsername: "username", + discordWebhookUrl: url, + discordPrefixMessage: "prefix", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing monitor", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + ping: "111" + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith(url, { + content: "prefix", + embeds: [ + { + color: 65280, + fields: [ + { + name: "Service Name", + value: "testing monitor", + }, + { + name: "Service URL", + value: "[Visit Service](https://www.google.com)", + }, + { + name: "Time (UTC)", + value: "example time", + }, + { + name: "Ping", + value: "111ms", + }, + ], + timestamp: "example time", + title: "✅ Your service testing monitor is up! ✅", + }, + ], + username: "username" + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when having heartbeat & monitor & service down", async () => { + + let response = {}; + axios.post.mockResolvedValueOnce(response); + + let notif = new Discord(); + let url = "https://example.com/webhook"; + let notificationConf = { + discordUsername: "username", + discordWebhookUrl: url, + discordPrefixMessage: "prefix", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing monitor", + }; + let heartbeatConf = { + status: DOWN, + msg: "some message", + time: "example time", + ping: "111" + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith(url, { + content: "prefix", + embeds: [ + { + color: 16711680, + fields: [ + { + name: "Service Name", + value: "testing monitor", + }, + { + name: "Service URL", + value: "[Visit Service](https://www.google.com)", + }, + { + name: "Time (UTC)", + value: "example time", + }, + { + name: "Error", + value: "some message", + }, + ], + timestamp: "example time", + title: "❌ Your service testing monitor went down. ❌", + }, + ], + username: "username" + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + + let notif = new Discord(); + let notificationConf = { + appriseURL: "appriseURL", + secretKey: "abc", + discordWebhookUrl: "https://example.com/webhook", + }; + let msg = "PassedInMessage"; + + try { + await notif.send(notificationConf, msg, null, null); + console.log("fail"); + expect("Error thrown").toBe(false); + } catch (e) { + //axios general error on catching another error is not the cleanest, but works. + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://example.com/webhook", { + content: "PassedInMessage", + username: "Uptime Kuma" + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call sendMail with proper data", async () => { + + let response = {}; + axios.post.mockResolvedValueOnce(response); + + let url = "https://example.com/webhook"; + let notificationConf = { + type: "discord", + discordUsername: "username", + discordWebhookUrl: url, + discordPrefixMessage: "prefix", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing monitor", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + ping: "111" + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith(url, { + content: "prefix", + embeds: [ + { + color: 65280, + fields: [ + { + name: "Service Name", + value: "testing monitor", + }, + { + name: "Service URL", + value: "[Visit Service](https://www.google.com)", + }, + { + name: "Time (UTC)", + value: "example time", + }, + { + name: "Ping", + value: "111ms", + }, + ], + timestamp: "example time", + title: "✅ Your service testing monitor is up! ✅", + }, + ], + username: "username" + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/feishu.js b/server/notification-providers/feishu.js index a3e3403..5ab8ca7 100644 --- a/server/notification-providers/feishu.js +++ b/server/notification-providers/feishu.js @@ -6,7 +6,6 @@ class Feishu extends NotificationProvider { name = "Feishu"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; let feishuWebHookUrl = notification.feishuWebHookUrl; try { @@ -18,7 +17,7 @@ class Feishu extends NotificationProvider { }, }; await axios.post(feishuWebHookUrl, testdata); - return okMsg; + return this.sendSuccess; } if (heartbeatJSON["status"] == DOWN) { @@ -45,7 +44,7 @@ class Feishu extends NotificationProvider { }, }; await axios.post(feishuWebHookUrl, downdata); - return okMsg; + return this.sendSuccess; } if (heartbeatJSON["status"] == UP) { @@ -72,7 +71,7 @@ class Feishu extends NotificationProvider { }, }; await axios.post(feishuWebHookUrl, updata); - return okMsg; + return this.sendSuccess; } } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/feishu.spec.js b/server/notification-providers/feishu.spec.js new file mode 100644 index 0000000..cb152f3 --- /dev/null +++ b/server/notification-providers/feishu.spec.js @@ -0,0 +1,174 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Feishu = require("./feishu"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Feishu(); + expect(notification.name).toBe("Feishu"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Feishu(); + let notificationConf = { + feishuWebHookUrl: "feishuWebHookUrl" + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("feishuWebHookUrl", { + content: { + post: { + zh_cn: { + content: [ + [ + { + tag: "text", + text: "[Up] some message\nTime (UTC): example time", + }, + ], + ], + title: "UptimeKuma Alert: testing", + }, + }, + }, + msg_type: "post", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Feishu(); + let notificationConf = { + feishuWebHookUrl: "feishuWebHookUrl" + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("feishuWebHookUrl", { + "content": { + "text": "PassedInMessage" + }, + "msg_type": "text" + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + + let notificationConf = { + feishuWebHookUrl: "feishuWebHookUrl" + + }; + let msg = "PassedInMessage"; + let notif = new Feishu(); + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("feishuWebHookUrl", { + content: { + text: "PassedInMessage", + }, + msg_type: "text", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "Feishu", + feishuWebHookUrl: "feishuWebHookUrl" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("feishuWebHookUrl", { + content: { + post: { + zh_cn: { + content: [ + [ + { + tag: "text", + text: "[Up] some message\nTime (UTC): example time", + }, + ], + ], + title: "UptimeKuma Alert: testing", + }, + }, + }, + msg_type: "post", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/gotify.js b/server/notification-providers/gotify.js index 0852618..dba6dea 100644 --- a/server/notification-providers/gotify.js +++ b/server/notification-providers/gotify.js @@ -6,7 +6,6 @@ class Gotify extends NotificationProvider { name = "gotify"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) { notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1); @@ -15,9 +14,9 @@ class Gotify extends NotificationProvider { "message": msg, "priority": notification.gotifyPriority || 8, "title": "Uptime-Kuma", - }) + }); - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/gotify.spec.js b/server/notification-providers/gotify.spec.js new file mode 100644 index 0000000..c88058d --- /dev/null +++ b/server/notification-providers/gotify.spec.js @@ -0,0 +1,152 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Gotify = require("./gotify"); + +beforeEach(() => { + axios.post.mockReset(); +}); +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Gotify(); + expect(notification.name).toBe("gotify"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Gotify(); + let notificationConf = { + gotifyserverurl: "url/", + gotifyPriority: 4, + gotifyapplicationToken: "token" + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("url/message?token=token", { + message: "PassedInMessage", + priority: 4, + title: "Uptime-Kuma", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Gotify(); + let notificationConf = { + gotifyserverurl: "url", + gotifyPriority: 4, + gotifyapplicationToken: "token" + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("url/message?token=token", { + message: "PassedInMessage", + priority: 4, + title: "Uptime-Kuma", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + + let notificationConf = { + gotifyserverurl: "url", + gotifyPriority: 4, + gotifyapplicationToken: "token" + }; + let msg = "PassedInMessage"; + let notif = new Gotify(); + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("url/message?token=token", { + message: "PassedInMessage", + priority: 4, + title: "Uptime-Kuma", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "gotify", + gotifyserverurl: "url", + gotifyPriority: 4, + gotifyapplicationToken: "token" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("url/message?token=token", { + message: "PassedInMessage", + priority: 4, + title: "Uptime-Kuma", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/line.js b/server/notification-providers/line.js index 327696e..a9c2f58 100644 --- a/server/notification-providers/line.js +++ b/server/notification-providers/line.js @@ -7,7 +7,6 @@ class Line extends NotificationProvider { name = "line"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { let lineAPIUrl = "https://api.line.me/v2/bot/message/push"; let config = { @@ -25,34 +24,34 @@ class Line extends NotificationProvider { "text": "Test Successful!" } ] - } - await axios.post(lineAPIUrl, testMessage, config) + }; + await axios.post(lineAPIUrl, testMessage, config); } else if (heartbeatJSON["status"] == DOWN) { let downMessage = { "to": notification.lineUserID, "messages": [ { "type": "text", - "text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] + "text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + "\n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] } ] - } - await axios.post(lineAPIUrl, downMessage, config) + }; + await axios.post(lineAPIUrl, downMessage, config); } else if (heartbeatJSON["status"] == UP) { let upMessage = { "to": notification.lineUserID, "messages": [ { "type": "text", - "text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] + "text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + "\n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] } ] - } - await axios.post(lineAPIUrl, upMessage, config) + }; + await axios.post(lineAPIUrl, upMessage, config); } - return okMsg; + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/line.spec.js b/server/notification-providers/line.spec.js new file mode 100644 index 0000000..97b8631 --- /dev/null +++ b/server/notification-providers/line.spec.js @@ -0,0 +1,232 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Line = require("./line"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Line(); + expect(notification.name).toBe("line"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Line(); + let notificationConf = { + type: "line", + lineUserID: "1234", + lineChannelAccessToken: "token" + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.line.me/v2/bot/message/push", { + messages: [ + { + text: "UptimeKuma Alert: [✅ Up]\nName: testing\nsome message\nTime (UTC): example time", + type: "text", + }, + ], + to: "1234", + }, { + headers: { + "Authorization": "Bearer token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + it("should call axios with the proper default data when DOWN", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Line(); + let notificationConf = { + type: "line", + lineUserID: "1234", + lineChannelAccessToken: "token" + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: DOWN, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.line.me/v2/bot/message/push", { + messages: [ + { + text: "UptimeKuma Alert: [🔴 Down]\nName: testing\nsome message\nTime (UTC): example time", + type: "text", + }, + ], + to: "1234", + }, { + headers: { + "Authorization": "Bearer token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Line(); + let notificationConf = { + type: "line", + lineUserID: "1234", + lineChannelAccessToken: "token" + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://api.line.me/v2/bot/message/push", { + messages: [ + { + text: "Test Successful!", + type: "text", + }, + ], + to: "1234", + }, { + headers: { + "Authorization": "Bearer token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + + let notificationConf = { + type: "line", + lineUserID: "1234", + lineChannelAccessToken: "token" + }; + let msg = "PassedInMessage"; + let notif = new Line(); + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://api.line.me/v2/bot/message/push", { + messages: [ + { + text: "Test Successful!", + type: "text", + }, + ], + to: "1234", + }, { + headers: { + "Authorization": "Bearer token", + "Content-Type": "application/json", + }, + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "line", + lineUserID: "1234", + lineChannelAccessToken: "token" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://api.line.me/v2/bot/message/push", { + messages: [ + { + text: "UptimeKuma Alert: [✅ Up]\nName: testing\nsome message\nTime (UTC): example time", + type: "text", + }, + ], + to: "1234", + }, { + headers: { + "Authorization": "Bearer token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/lunasea.js b/server/notification-providers/lunasea.js index c41f400..6b7ccb4 100644 --- a/server/notification-providers/lunasea.js +++ b/server/notification-providers/lunasea.js @@ -7,39 +7,38 @@ class LunaSea extends NotificationProvider { name = "lunasea"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice + let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice; try { if (heartbeatJSON == null) { let testdata = { "title": "Uptime Kuma Alert", "body": "Testing Successful.", - } - await axios.post(lunaseadevice, testdata) - return okMsg; + }; + await axios.post(lunaseadevice, testdata); + return this.sendSuccess; } if (heartbeatJSON["status"] == DOWN) { let downdata = { "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(lunaseadevice, downdata) - return okMsg; + }; + await axios.post(lunaseadevice, downdata); + return this.sendSuccess; } if (heartbeatJSON["status"] == UP) { let updata = { "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(lunaseadevice, updata) - return okMsg; + }; + await axios.post(lunaseadevice, updata); + return this.sendSuccess; } } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/lunasea.spec.js b/server/notification-providers/lunasea.spec.js new file mode 100644 index 0000000..fd9639d --- /dev/null +++ b/server/notification-providers/lunasea.spec.js @@ -0,0 +1,176 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const LunaSea = require("./lunasea"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new LunaSea(); + expect(notification.name).toBe("lunasea"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new LunaSea(); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://notify.lunasea.app/v1/custom/device/1234", { + "body": "[✅ Up] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + }); + expect(res).toBe("Sent Successfully."); + }); + it("should call axios with the proper default data when DOWN", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new LunaSea(); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: DOWN, + msg: "some message", + time: "example time", + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://notify.lunasea.app/v1/custom/device/1234", { + "body": "[🔴 Down] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new LunaSea(); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://notify.lunasea.app/v1/custom/device/1234", { + "body": "Testing Successful.", + "title": "Uptime Kuma Alert", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new LunaSea(); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let msg = "PassedInMessage"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://notify.lunasea.app/v1/custom/device/1234", { + + "body": "Testing Successful.", + "title": "Uptime Kuma Alert" }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://notify.lunasea.app/v1/custom/device/1234", { + "body": "[✅ Up] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/matrix.js b/server/notification-providers/matrix.js index c1054fc..26a85ff 100644 --- a/server/notification-providers/matrix.js +++ b/server/notification-providers/matrix.js @@ -7,7 +7,6 @@ class Matrix extends NotificationProvider { name = "matrix"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; const size = 20; const randomString = encodeURIComponent( @@ -35,7 +34,7 @@ class Matrix extends NotificationProvider { }; await axios.put(`${notification.homeserverUrl}/_matrix/client/r0/rooms/${roomId}/send/m.room.message/${randomString}`, data, config); - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/matrix.spec.js b/server/notification-providers/matrix.spec.js new file mode 100644 index 0000000..b70c569 --- /dev/null +++ b/server/notification-providers/matrix.spec.js @@ -0,0 +1,171 @@ +jest.mock("axios", () => ({ + put: jest.fn(), +})); +jest.mock("crypto", () => ({ + randomBytes: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Matrix = require("./matrix"); +const Crypto = require("crypto"); + +beforeEach(() => { + axios.put.mockReset(); + Crypto.randomBytes.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Matrix(); + expect(notification.name).toBe("matrix"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.put.mockResolvedValueOnce(response); + Crypto.randomBytes.mockReturnValueOnce(Buffer.from("abcd")); + + let notif = new Matrix(); + + let msg = "PassedInMessage"; + let notificationConf = { + type: "matrix", + internalRoomId: "1234", + accessToken: "abcd", + homeserverUrl: "www.example.com", + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.put).toHaveBeenCalledWith("www.example.com/_matrix/client/r0/rooms/1234/send/m.room.message/YWJjZA%3D%3D", { + body: "PassedInMessage", + msgtype: "m.text" + }, { + headers: { + "Authorization": "Bearer abcd" + } + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.put.mockResolvedValueOnce(response); + Crypto.randomBytes.mockReturnValueOnce(Buffer.from("abcd")); + + let notif = new Matrix(); + let notificationConf = { + type: "matrix", + internalRoomId: "1234", + accessToken: "abcd", + homeserverUrl: "www.example.com", + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.put).toHaveBeenCalledWith("www.example.com/_matrix/client/r0/rooms/1234/send/m.room.message/YWJjZA%3D%3D", { + body: "PassedInMessage", + msgtype: "m.text" + }, { + headers: { + "Authorization": "Bearer abcd" + } + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.put.mockImplementation(() => { + throw new Error("Test Error"); + }); + Crypto.randomBytes.mockReturnValueOnce(Buffer.from("abcd")); + + let notif = new Matrix(); + let notificationConf = { + type: "matrix", + internalRoomId: "1234", + accessToken: "abcd", + homeserverUrl: "www.example.com", + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.put).toHaveBeenCalledWith("www.example.com/_matrix/client/r0/rooms/1234/send/m.room.message/YWJjZA%3D%3D", { + body: "PassedInMessage", + msgtype: "m.text" + }, { + headers: { + "Authorization": "Bearer abcd" + } + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.put.mockResolvedValueOnce(response); + Crypto.randomBytes.mockReturnValueOnce(Buffer.from("abcd")); + + let notificationConf = { + type: "matrix", + internalRoomId: "1234", + accessToken: "abcd", + homeserverUrl: "www.example.com", + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.put).toHaveBeenCalledWith("www.example.com/_matrix/client/r0/rooms/1234/send/m.room.message/YWJjZA%3D%3D", { + body: "PassedInMessage", + msgtype: "m.text" + }, { + headers: { + "Authorization": "Bearer abcd" + } + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/mattermost.js b/server/notification-providers/mattermost.js index d776284..1d25811 100644 --- a/server/notification-providers/mattermost.js +++ b/server/notification-providers/mattermost.js @@ -7,7 +7,6 @@ class Mattermost extends NotificationProvider { name = "mattermost"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; // If heartbeatJSON is null, assume we're testing. @@ -15,9 +14,9 @@ class Mattermost extends NotificationProvider { let mattermostTestData = { username: mattermostUserName, text: msg, - } - await axios.post(notification.mattermostWebhookUrl, mattermostTestData) - return okMsg; + }; + await axios.post(notification.mattermostWebhookUrl, mattermostTestData); + return this.sendSuccess; } const mattermostChannel = notification.mattermostchannel; @@ -36,12 +35,12 @@ class Mattermost extends NotificationProvider { fallback: "Your " + monitorJSON["name"] + - " service went down.", + " service went down!", color: "#FF0000", title: "❌ " + monitorJSON["name"] + - " service went down. ❌", + " service went down! ❌", title_link: monitorJSON["url"], fields: [ { @@ -67,7 +66,7 @@ class Mattermost extends NotificationProvider { notification.mattermostWebhookUrl, mattermostdowndata ); - return okMsg; + return this.sendSuccess; } else if (heartbeatJSON["status"] == UP) { let mattermostupdata = { username: mattermostUserName, @@ -111,7 +110,7 @@ class Mattermost extends NotificationProvider { notification.mattermostWebhookUrl, mattermostupdata ); - return okMsg; + return this.sendSuccess; } } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/mattermost.spec.js b/server/notification-providers/mattermost.spec.js new file mode 100644 index 0000000..fa3979b --- /dev/null +++ b/server/notification-providers/mattermost.spec.js @@ -0,0 +1,297 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Mattermost = require("./mattermost"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Mattermost(); + expect(notification.name).toBe("mattermost"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Mattermost(); + let notificationConf = { + type: "mattermost", + mattermostchannel: "1234", + mattermosticonemo: "😀", + mattermosticonurl: "www.testing.com", + mattermostWebhookUrl: "www.example.com/webhook", + mattermostusername: "username", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + ping: "123", + time: "example time", + }; + let msg = "PassedInMessage"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("www.example.com/webhook", { + "attachments": [ + { + "color": "#32CD32", + "fallback": "Your testing service went up!", + "fields": [ + { + "short": true, + "title": "Service Name", + "value": "testing", + }, + { + "short": true, + "title": "Time (UTC)", + "value": "example time", + }, + { + "short": false, + "title": "Ping", + "value": "123ms", + }, + ], + "title": "✅ testing service went up! ✅", + "title_link": "https://www.google.com", + }, + ], + "channel": "1234", + "icon_emoji": "😀", + "icon_url": "www.testing.com", + "text": "Uptime Kuma Alert", + "username": "username", + }); + expect(res).toBe("Sent Successfully."); + }); + it("should call axios with the proper default data when DOWN", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Mattermost(); + let notificationConf = { + type: "mattermost", + mattermostchannel: "1234", + mattermosticonemo: "😀", + mattermosticonurl: "www.testing.com", + mattermostWebhookUrl: "www.example.com/webhook", + mattermostusername: "username", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: DOWN, + msg: "some message", + ping: "123", + time: "example time", + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("www.example.com/webhook", { + "attachments": [ + { + "color": "#FF0000", + "fallback": "Your testing service went down!", + "fields": [ + { + "short": true, + "title": "Service Name", + "value": "testing", + }, + { + "short": true, + "title": "Time (UTC)", + "value": "example time", + }, + { + "short": false, + "title": "Error", + "value": "some message", + }, + ], + "title": "❌ testing service went down! ❌", + "title_link": "https://www.google.com", + }, + ], + "channel": "1234", + "icon_emoji": "😀", + "icon_url": "www.testing.com", + "text": "Uptime Kuma Alert", + "username": "username", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Mattermost(); + let notificationConf = { + type: "mattermost", + mattermostchannel: "1234", + mattermosticonemo: "😀", + mattermosticonurl: "www.testing.com", + mattermostWebhookUrl: "www.example.com/webhook", + mattermostusername: "username", + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("www.example.com/webhook", { + + "text": "PassedInMessage", + "username": "username" + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Mattermost(); + let notificationConf = { + type: "mattermost", + mattermostchannel: "1234", + mattermosticonemo: "😀", + mattermosticonurl: "www.testing.com", + mattermostWebhookUrl: "www.example.com/webhook", + mattermostusername: "username", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + ping: "123", + time: "example time", + }; + let msg = "PassedInMessage"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("www.example.com/webhook", { + + "text": "PassedInMessage", + "username": "username" + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "mattermost", + mattermostchannel: "1234", + mattermosticonemo: "😀", + mattermosticonurl: "www.testing.com", + mattermostWebhookUrl: "www.example.com/webhook", + mattermostusername: "username", + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + ping: "123", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "PassedInMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("www.example.com/webhook", { + "attachments": [ + { + "color": "#32CD32", + "fallback": "Your testing service went up!", + "fields": [ + { + "short": true, + "title": "Service Name", + "value": "testing", + }, + { + "short": true, + "title": "Time (UTC)", + "value": "example time", + }, + { + "short": false, + "title": "Ping", + "value": "123ms", + }, + ], + "title": "✅ testing service went up! ✅", + "title_link": "https://www.google.com", + }, + ], + "channel": "1234", + "icon_emoji": "😀", + "icon_url": "www.testing.com", + "text": "Uptime Kuma Alert", + "username": "username", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/notification-provider.js b/server/notification-providers/notification-provider.js index 61c6242..3ccff04 100644 --- a/server/notification-providers/notification-provider.js +++ b/server/notification-providers/notification-provider.js @@ -6,6 +6,8 @@ class NotificationProvider { */ name = undefined; + sendSuccess = "Sent Successfully."; + /** * @param notification : BeanModel * @param msg : string General Message @@ -25,11 +27,11 @@ class NotificationProvider { if (typeof error.response.data === "string") { msg += error.response.data; } else { - msg += JSON.stringify(error.response.data) + msg += JSON.stringify(error.response.data); } } - throw new Error(msg) + throw new Error(msg); } } diff --git a/server/notification-providers/notification-provider.spec.js b/server/notification-providers/notification-provider.spec.js new file mode 100644 index 0000000..1f6f037 --- /dev/null +++ b/server/notification-providers/notification-provider.spec.js @@ -0,0 +1,40 @@ +// jest.mock("nodemailer", () => ({ +// createTransport: jest.fn(), +// })); + +// const mockNodeMailer = require("nodemailer"); + +const NotificationProvider = require("./notification-provider"); + +beforeEach(() => { + // mockNodeMailer.createTransport.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new NotificationProvider(); + expect(notification.name).toBe(undefined); + }); +}); + +describe("notification to error if blank notification called", () => { + it("should respond with an error if just called.", async () => { + + let notif = new NotificationProvider(); + let notificationConf = { + type: "telegram", + telegramBotToken: "abc", + telegramChatID: "123", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Have to override Notification.send(...)"); + } + + }); + +}); diff --git a/server/notification-providers/octopush.js b/server/notification-providers/octopush.js index 9d77aa5..6ef8e39 100644 --- a/server/notification-providers/octopush.js +++ b/server/notification-providers/octopush.js @@ -6,7 +6,6 @@ class Octopush extends NotificationProvider { name = "octopush"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { // Default - V2 @@ -30,7 +29,7 @@ class Octopush extends NotificationProvider { "purpose": "alert", "sender": notification.octopushSenderName }; - await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config) + await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config); } else if (notification.octopushVersion == 1) { let data = { "user_login": notification.octopushDMLogin, @@ -49,12 +48,12 @@ class Octopush extends NotificationProvider { }, params: data }; - await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config) + await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config); } else { throw new Error("Unknown Octopush version!"); } - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/octopush.spec.js b/server/notification-providers/octopush.spec.js new file mode 100644 index 0000000..75ac667 --- /dev/null +++ b/server/notification-providers/octopush.spec.js @@ -0,0 +1,245 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const Octopush = require("./octopush"); + +beforeEach(() => { + axios.post.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Octopush(); + expect(notification.name).toBe("octopush"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when version 2", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Octopush(); + let notificationConf = { + type: "octopush", + octopushVersion: 2, + octopushAPIKey: "key", + octopushLogin: "login", + octopushPhoneNumber: "number", + octopushSMSType: "type", + octopushSenderName: "sender" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.octopush.com/v1/public/sms-campaign/send", { + "purpose": "alert", + "recipients": [{ "phone_number": "number" }], + "sender": "sender", + "text": "PassedInMessage", + "type": "type" + }, { + "headers": { + "api-key": "key", + "api-login": "login", + "cache-control": "no-cache" + } + }); + expect(res).toBe("Sent Successfully."); + }); + it("should call axios with the proper default data when version 1", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Octopush(); + let notificationConf = { + type: "octopush", + octopushVersion: 1, + octopushDMAPIKey: "key", + octopushDMLogin: "login", + octopushDMPhoneNumber: "number", + octopushDMSMSType: "sms_premium", + octopushDMSenderName: "sender" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://www.octopush-dm.com/api/sms/json", { + + }, { + "headers": { + "cache-control": "no-cache" + }, + "params": { + "api_key": "key", + "sms_recipients": "number", + "sms_sender": "sender", + "sms_text": "PassedInMessage", + "sms_type": "FR", + "transactional": "1", + "user_login": "login" + } + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Octopush(); + let notificationConf = { + type: "lunasea", + lunaseaDevice: "1234", + }; + let msg = "PassedInMessage"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://api.octopush.com/v1/public/sms-campaign/send", { + "purpose": "alert", + "recipients": [{ "phone_number": undefined }], + "sender": undefined, + "text": "PassedInMessage", + "type": undefined + }, { + "headers": { + "api-key": undefined, + "api-login": undefined, + "cache-control": "no-cache" + } + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Octopush(); + let notificationConf = { + type: "octopush", + octopushVersion: 2, + octopushAPIKey: "key", + octopushLogin: "login", + octopushPhoneNumber: "number", + octopushSMSType: "type", + octopushSenderName: "sender" + }; + let msg = "PassedInMessage"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://api.octopush.com/v1/public/sms-campaign/send", { + "purpose": "alert", + "recipients": [{ "phone_number": "number" }], + "sender": "sender", + "text": "PassedInMessage", + "type": "type" + }, { + "headers": { + "api-key": "key", + "api-login": "login", + "cache-control": "no-cache" + } + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "octopush", + octopushVersion: 2, + octopushAPIKey: "key", + octopushLogin: "login", + octopushPhoneNumber: "number", + octopushSMSType: "type", + octopushSenderName: "sender" + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "Passed😀InMessage", monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://api.octopush.com/v1/public/sms-campaign/send", { + "purpose": "alert", + "recipients": [{ "phone_number": "number" }], + "sender": "sender", + "text": "PassedInMessage", + "type": "type" + }, { + "headers": { + "api-key": "key", + "api-login": "login", + "cache-control": "no-cache" + } + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/promosms.js b/server/notification-providers/promosms.js index 362ef71..4f0e526 100644 --- a/server/notification-providers/promosms.js +++ b/server/notification-providers/promosms.js @@ -6,13 +6,12 @@ class PromoSMS extends NotificationProvider { name = "promosms"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { let config = { headers: { "Content-Type": "application/json", - "Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString('base64'), + "Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString("base64"), "Accept": "text/json", } }; @@ -30,8 +29,8 @@ class PromoSMS extends NotificationProvider { let error = "Something gone wrong. Api returned " + resp.data.response.status + "."; this.throwGeneralAxiosError(error); } - - return okMsg; + + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/promosms.spec.js b/server/notification-providers/promosms.spec.js new file mode 100644 index 0000000..6802341 --- /dev/null +++ b/server/notification-providers/promosms.spec.js @@ -0,0 +1,193 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const PromoSMS = require("./promosms"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new PromoSMS(); + expect(notification.name).toBe("promosms"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + response: { + status: 0 + }, + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new PromoSMS(); + let notificationConf = { + type: "promosms", + promosmsLogin: "login", + promosmsPassword: "password", + promosmsPhoneNumber: "number", + promosmsSMSType: 1, + promosmsSenderName: "sender" + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://promosms.com/api/rest/v3_2/sms", { + "recipients": [ + "number", + ], + "sender": "sender", + "text": "PassedInMessage", + "type": 1, + }, { + "headers": { + "Accept": "text/json", + "Authorization": "Basic bG9naW46cGFzc3dvcmQ=", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + response: { + status: 0 + }, + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new PromoSMS(); + let notificationConf = { + type: "promosms", + promosmsLogin: "login", + promosmsPassword: "password", + promosmsPhoneNumber: "number", + promosmsSMSType: 1, + promosmsSenderName: "sender" + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://promosms.com/api/rest/v3_2/sms", { + "recipients": [ + "number", + ], + "sender": "sender", + "text": "PassedInMessage", + "type": 1, + }, { + "headers": { + "Accept": "text/json", + "Authorization": "Basic bG9naW46cGFzc3dvcmQ=", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new PromoSMS(); + let notificationConf = { + type: "promosms", + promosmsLogin: "login", + promosmsPassword: "password", + promosmsPhoneNumber: "number", + promosmsSMSType: 1, + promosmsSenderName: "sender" + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://promosms.com/api/rest/v3_2/sms", { + "recipients": [ + "number", + ], + "sender": "sender", + "text": "PassedInMessage", + "type": 1, + }, { + "headers": { + "Accept": "text/json", + "Authorization": "Basic bG9naW46cGFzc3dvcmQ=", + "Content-Type": "application/json", + }, + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + response: { + status: 0 + }, + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "promosms", + promosmsLogin: "login", + promosmsPassword: "password", + promosmsPhoneNumber: "number", + promosmsSMSType: 1, + promosmsSenderName: "sender" + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://promosms.com/api/rest/v3_2/sms", { + "recipients": [ + "number", + ], + "sender": "sender", + "text": "PassedInMessage", + "type": 1, + }, { + "headers": { + "Accept": "text/json", + "Authorization": "Basic bG9naW46cGFzc3dvcmQ=", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/pushbullet.js b/server/notification-providers/pushbullet.js index c7b824a..9de5b61 100644 --- a/server/notification-providers/pushbullet.js +++ b/server/notification-providers/pushbullet.js @@ -8,7 +8,6 @@ class Pushbullet extends NotificationProvider { name = "pushbullet"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { let pushbulletUrl = "https://api.pushbullet.com/v2/pushes"; @@ -23,26 +22,26 @@ class Pushbullet extends NotificationProvider { "type": "note", "title": "Uptime Kuma Alert", "body": "Testing Successful.", - } - await axios.post(pushbulletUrl, testdata, config) + }; + await axios.post(pushbulletUrl, testdata, config); } else if (heartbeatJSON["status"] == DOWN) { let downdata = { "type": "note", "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(pushbulletUrl, downdata, config) + }; + await axios.post(pushbulletUrl, downdata, config); } else if (heartbeatJSON["status"] == UP) { let updata = { "type": "note", "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(pushbulletUrl, updata, config) + }; + await axios.post(pushbulletUrl, updata, config); } - return okMsg; + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/pushbullet.spec.js b/server/notification-providers/pushbullet.spec.js new file mode 100644 index 0000000..8958b5e --- /dev/null +++ b/server/notification-providers/pushbullet.spec.js @@ -0,0 +1,201 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Pushbullet = require("./pushbullet"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Pushbullet(); + expect(notification.name).toBe("pushbullet"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushbullet(); + let notificationConf = { + type: "pushbullet", + pushbulletAccessToken: "token", + }; + let monitorConf = { + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushbullet.com/v2/pushes", { + "body": "[✅ Up] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + "type": "note", + }, { + "headers": { + "Access-Token": "token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushbullet(); + let notificationConf = { + type: "pushbullet", + pushbulletAccessToken: "token", + }; + let monitorConf = { + name: "testing", + }; + let heartbeatConf = { + status: DOWN, + msg: "some message", + time: "example time", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushbullet.com/v2/pushes", { + "body": "[🔴 Down] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + "type": "note", + }, { + "headers": { + "Access-Token": "token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushbullet(); + let notificationConf = { + type: "pushbullet", + pushbulletAccessToken: "token", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushbullet.com/v2/pushes", { + "body": "Testing Successful.", + "title": "Uptime Kuma Alert", + "type": "note", + }, { + "headers": { + "Access-Token": "token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Pushbullet(); + let notificationConf = { + type: "pushbullet", + pushbulletAccessToken: "token", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://api.pushbullet.com/v2/pushes", { + "body": "Testing Successful.", + "title": "Uptime Kuma Alert", + "type": "note", + }, { + "headers": { + "Access-Token": "token", + "Content-Type": "application/json", + }, + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "pushbullet", + pushbulletAccessToken: "token", + }; + let monitorConf = { + name: "testing", + }; + let heartbeatConf = { + status: UP, + msg: "some message", + time: "example time", + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://api.pushbullet.com/v2/pushes", { + "body": "[✅ Up] some message\nTime (UTC): example time", + "title": "UptimeKuma Alert: testing", + "type": "note", + }, { + "headers": { + "Access-Token": "token", + "Content-Type": "application/json", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/pushover.js b/server/notification-providers/pushover.js index 77ef1a3..76aa059 100644 --- a/server/notification-providers/pushover.js +++ b/server/notification-providers/pushover.js @@ -6,8 +6,7 @@ class Pushover extends NotificationProvider { name = "pushover"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let pushoverlink = "https://api.pushover.net/1/messages.json" + let pushoverlink = "https://api.pushover.net/1/messages.json"; try { if (heartbeatJSON == null) { @@ -21,9 +20,9 @@ class Pushover extends NotificationProvider { "retry": "30", "expire": "3600", "html": 1, - } - await axios.post(pushoverlink, data) - return okMsg; + }; + await axios.post(pushoverlink, data); + return this.sendSuccess; } let data = { @@ -36,11 +35,11 @@ class Pushover extends NotificationProvider { "retry": "30", "expire": "3600", "html": 1, - } - await axios.post(pushoverlink, data) - return okMsg; + }; + await axios.post(pushoverlink, data); + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/pushover.spec.js b/server/notification-providers/pushover.spec.js new file mode 100644 index 0000000..d6ee4f7 --- /dev/null +++ b/server/notification-providers/pushover.spec.js @@ -0,0 +1,177 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Pushover = require("./pushover"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Pushover(); + expect(notification.name).toBe("pushover"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushover(); + let notificationConf = { + type: "octopush", + pushoveruserkey: "123", + pushoverapptoken: "token", + pushoversounds: "ding", + pushoverpriority: "6", + pushovertitle: "Important Title!", + }; + let monitorConf = { + }; + let heartbeatConf = { + time: "example time", + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushover.net/1/messages.json", { + "expire": "3600", + "html": 1, + "message": "Uptime Kuma Alert\n\nMessage:PassedInMessage😀\nTime (UTC):example time", + "priority": "6", + "retry": "30", + "sound": "ding", + "title": "Important Title!", + "token": "token", + "user": "123", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushover(); + let notificationConf = { + type: "octopush", + pushoveruserkey: "123", + pushoverapptoken: "token", + pushoversounds: "ding", + pushoverpriority: "6", + pushovertitle: "Important Title!", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushover.net/1/messages.json", { + "expire": "3600", + "html": 1, + "message": "Uptime Kuma Pushover testing successful.", + "priority": "6", + "retry": "30", + "sound": "ding", + "title": "Important Title!", + "token": "token", + "user": "123", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Pushover(); + let notificationConf = { + type: "octopush", + pushoveruserkey: "123", + pushoverapptoken: "token", + pushoversounds: "ding", + pushoverpriority: "6", + pushovertitle: "Important Title!", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://api.pushover.net/1/messages.json", { + "expire": "3600", + "html": 1, + "message": "Uptime Kuma Pushover testing successful.", + "priority": "6", + "retry": "30", + "sound": "ding", + "title": "Important Title!", + "token": "token", + "user": "123", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "pushover", + pushoveruserkey: "123", + pushoverapptoken: "token", + pushoversounds: "ding", + pushoverpriority: "6", + pushovertitle: "Important Title!", + }; + let monitorConf = { + }; + let heartbeatConf = { + time: "example time", + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://api.pushover.net/1/messages.json", { + "expire": "3600", + "html": 1, + "message": "Uptime Kuma Alert\n\nMessage:PassedInMessage😀\nTime (UTC):example time", + "priority": "6", + "retry": "30", + "sound": "ding", + "title": "Important Title!", + "token": "token", + "user": "123", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/pushy.js b/server/notification-providers/pushy.js index 2bb8993..f18c915 100644 --- a/server/notification-providers/pushy.js +++ b/server/notification-providers/pushy.js @@ -6,7 +6,6 @@ class Pushy extends NotificationProvider { name = "pushy"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, { @@ -19,10 +18,10 @@ class Pushy extends NotificationProvider { "badge": 1, "sound": "ping.aiff" } - }) - return okMsg; + }); + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/pushy.spec.js b/server/notification-providers/pushy.spec.js new file mode 100644 index 0000000..4fada3d --- /dev/null +++ b/server/notification-providers/pushy.spec.js @@ -0,0 +1,161 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Pushy = require("./pushy"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Pushy(); + expect(notification.name).toBe("pushy"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushy(); + let notificationConf = { + pushyAPIKey: "key", + pushyToken: "token" + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushy.me/push?api_key=key", { + "data": { + "message": "Uptime-Kuma", + }, + "notification": { + "badge": 1, + "body": "PassedInMessage😀", + "sound": "ping.aiff", + }, + "to": "token", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Pushy(); + let notificationConf = { + pushyAPIKey: "key", + pushyToken: "token" + }; + + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://api.pushy.me/push?api_key=key", { + "data": { + "message": "Uptime-Kuma", + }, + "notification": { + "badge": 1, + "body": "PassedInMessage😀", + "sound": "ping.aiff", + }, + "to": "token", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Pushy(); + let notificationConf = { + pushyAPIKey: "key", + pushyToken: "token" + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://api.pushy.me/push?api_key=key", { + "data": { + "message": "Uptime-Kuma", + }, + "notification": { + "badge": 1, + "body": "PassedInMessage😀", + "sound": "ping.aiff", + }, + "to": "token", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "pushy", + pushyAPIKey: "key", + pushyToken: "token" + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://api.pushy.me/push?api_key=key", { + "data": { + "message": "Uptime-Kuma", + }, + "notification": { + "badge": 1, + "body": "PassedInMessage😀", + "sound": "ping.aiff", + }, + "to": "token", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/rocket-chat.js b/server/notification-providers/rocket-chat.js index 25b0b94..28327b0 100644 --- a/server/notification-providers/rocket-chat.js +++ b/server/notification-providers/rocket-chat.js @@ -9,7 +9,6 @@ class RocketChat extends NotificationProvider { name = "rocket.chat"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { let data = { @@ -19,7 +18,7 @@ class RocketChat extends NotificationProvider { "icon_emoji": notification.rocketiconemo, }; await axios.post(notification.rocketwebhookURL, data); - return okMsg; + return this.sendSuccess; } const time = heartbeatJSON["time"]; @@ -55,7 +54,7 @@ class RocketChat extends NotificationProvider { } await axios.post(notification.rocketwebhookURL, data); - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/rocket-chat.spec.js b/server/notification-providers/rocket-chat.spec.js new file mode 100644 index 0000000..a039571 --- /dev/null +++ b/server/notification-providers/rocket-chat.spec.js @@ -0,0 +1,221 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +jest.mock("../util-server"); + +const axios = require("axios"); +const { setting } = require("../util-server"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); + setting.mockReset(); +}); +const RocketChat = require("./rocket-chat"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new RocketChat(); + expect(notification.name).toBe("rocket.chat"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when UP", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + setting.mockResolvedValueOnce("base.com"); + let notif = new RocketChat(); + let notificationConf = { + rocketchannel: "channel", + rocketusername: "user", + rocketiconemo: "😀", + rocketwebhookURL: "example.com", + }; + let monitorConf = { + id: "123" + }; + let heartbeatConf = { + status: UP, + time: "some time" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("example.com", { + "attachments": [ + { + "color": "#32cd32", + "text": "*Message*\nPassedInMessage😀", + "title": "Uptime Kuma Alert *Time (UTC)*\nsome time", + "title_link": "base.com/dashboard/123", + }, + ], + "channel": "channel", + "icon_emoji": "😀", + "text": "Uptime Kuma Alert", + "username": "user", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper default data when DOWN", async () => { + + let response = { + data: { + Message: "OK" + } + }; + setting.mockResolvedValueOnce("base.com"); + axios.post.mockResolvedValueOnce(response); + + let notif = new RocketChat(); + let notificationConf = { + rocketchannel: "channel", + rocketusername: "user", + rocketiconemo: "😀", + rocketwebhookURL: "example.com", + }; + let monitorConf = { + id: "123" + }; + let heartbeatConf = { + status: DOWN, + time: "some time" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("example.com", { + "attachments": [ + { + "color": "#ff0000", + "text": "*Message*\nPassedInMessage😀", + "title": "Uptime Kuma Alert *Time (UTC)*\nsome time", + "title_link": "base.com/dashboard/123", + }, + ], + "channel": "channel", + "icon_emoji": "😀", + "text": "Uptime Kuma Alert", + "username": "user", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + setting.mockResolvedValueOnce("base.com"); + axios.post.mockResolvedValueOnce(response); + + let notif = new RocketChat(); + let notificationConf = { + rocketchannel: "channel", + rocketusername: "user", + rocketiconemo: "😀", + rocketwebhookURL: "example.com", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("example.com", { + "channel": "channel", + "icon_emoji": "😀", + "text": "PassedInMessage😀", + "username": "user", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + setting.mockResolvedValueOnce("base.com"); + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new RocketChat(); + let notificationConf = { + rocketchannel: "channel", + rocketusername: "user", + rocketiconemo: "😀", + rocketwebhookURL: "example.com", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("example.com", { + "channel": "channel", + "icon_emoji": "😀", + "text": "PassedInMessage😀", + "username": "user", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + setting.mockResolvedValueOnce("base.com"); + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "rocket.chat", + rocketchannel: "channel", + rocketusername: "user", + rocketiconemo: "😀", + rocketwebhookURL: "example.com", + }; + let monitorConf = { + id: "123" + }; + let heartbeatConf = { + status: UP, + time: "some time" + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("example.com", { + "attachments": [ + { + "color": "#32cd32", + "text": "*Message*\nPassedInMessage😀", + "title": "Uptime Kuma Alert *Time (UTC)*\nsome time", + "title_link": "base.com/dashboard/123", + }, + ], + "channel": "channel", + "icon_emoji": "😀", + "text": "Uptime Kuma Alert", + "username": "user", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/signal.js b/server/notification-providers/signal.js index fee6575..eb58eb2 100644 --- a/server/notification-providers/signal.js +++ b/server/notification-providers/signal.js @@ -6,7 +6,6 @@ class Signal extends NotificationProvider { name = "signal"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { let data = { @@ -16,10 +15,10 @@ class Signal extends NotificationProvider { }; let config = {}; - await axios.post(notification.signalURL, data, config) - return okMsg; + await axios.post(notification.signalURL, data, config); + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/signal.spec.js b/server/notification-providers/signal.spec.js new file mode 100644 index 0000000..6b8fd71 --- /dev/null +++ b/server/notification-providers/signal.spec.js @@ -0,0 +1,175 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Signal = require("./signal"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Signal(); + expect(notification.name).toBe("signal"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Signal(); + let notificationConf = { + type: "signal", + signalNumber: "appriseURL", + signalRecipients: "asd asd, age, ge, wrh werh ,werh ,er h,as", + signalURL: "https://example.com/webhook", + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("https://example.com/webhook", { + "message": "PassedInMessage😀", + "number": "appriseURL", + "recipients": [ + "asdasd", + "age", + "ge", + "wrhwerh", + "werh", + "erh", + "as", + ], + }, {}); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Signal(); + let notificationConf = { + type: "signal", + signalNumber: "appriseURL", + signalRecipients: "asd asd, age, ge, wrh werh ,werh ,er h,as", + signalURL: "https://example.com/webhook", + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("https://example.com/webhook", { + "message": "PassedInMessage😀", + "number": "appriseURL", + "recipients": [ + "asdasd", + "age", + "ge", + "wrhwerh", + "werh", + "erh", + "as", + ], + }, {}); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Signal(); + let notificationConf = { + type: "signal", + signalNumber: "appriseURL", + signalRecipients: "asd asd, age, ge, wrh werh ,werh ,er h,as", + signalURL: "https://example.com/webhook", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("https://example.com/webhook", { + "message": "PassedInMessage😀", + "number": "appriseURL", + "recipients": [ + "asdasd", + "age", + "ge", + "wrhwerh", + "werh", + "erh", + "as", + ], + }, {}); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "signal", + signalNumber: "appriseURL", + signalRecipients: "asd asd, age, ge, wrh werh ,werh ,er h,as", + signalURL: "https://example.com/webhook", + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("https://example.com/webhook", { + "message": "PassedInMessage😀", + "number": "appriseURL", + "recipients": [ + "asdasd", + "age", + "ge", + "wrhwerh", + "werh", + "erh", + "as", + ], + }, {}); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/slack.js b/server/notification-providers/slack.js index b4dad6f..d7ef721 100644 --- a/server/notification-providers/slack.js +++ b/server/notification-providers/slack.js @@ -25,7 +25,6 @@ class Slack extends NotificationProvider { } async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { let data = { @@ -35,7 +34,7 @@ class Slack extends NotificationProvider { "icon_emoji": notification.slackiconemo, }; await axios.post(notification.slackwebhookURL, data); - return okMsg; + return this.sendSuccess; } const time = heartbeatJSON["time"]; @@ -88,7 +87,7 @@ class Slack extends NotificationProvider { } await axios.post(notification.slackwebhookURL, data); - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/slack.spec.js b/server/notification-providers/slack.spec.js new file mode 100644 index 0000000..a360704 --- /dev/null +++ b/server/notification-providers/slack.spec.js @@ -0,0 +1,252 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +jest.mock("../util-server"); +const { setting } = require("../util-server"); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + setting.mockReset(); + axios.post.mockReset(); +}); +const Slack = require("./slack"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Slack(); + expect(notification.name).toBe("slack"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + setting.mockResolvedValueOnce("base.com"); + + let notif = new Slack(); + + let notificationConf = { + type: "slack", + slackchannel: "chan", + slackusername: "name", + slackiconemo: "😀", + slackwebhookURL: "www.slack.com/webhook" + }; + let monitorConf = { + name: "testing monitor", + id: "123", + }; + let heartbeatConf = { + time: "test time" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("www.slack.com/webhook", { + + "blocks": [ + { + "text": { + "text": "Uptime Kuma Alert", + "type": "plain_text", + }, + "type": "header", + }, + { + "fields": [ + { + "text": "*Message*\nPassedInMessage😀", + "type": "mrkdwn", + }, + { + "text": "*Time (UTC)*\ntest time", + "type": "mrkdwn", + }, + ], + "type": "section", + }, + { + "elements": [ + { + "text": { + "text": "Visit Uptime Kuma", + "type": "plain_text", + }, + "type": "button", + "url": "base.com/dashboard/123", + "value": "Uptime-Kuma", + }, + ], + "type": "actions", + }, + ], + "channel": "chan", + "icon_emoji": "😀", + "text": "Uptime Kuma Alert: testing monitor", + "username": "name", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + setting.mockResolvedValueOnce("base.com"); + + let notif = new Slack(); + + let notificationConf = { + type: "slack", + slackchannel: "chan", + slackusername: "name", + slackiconemo: "😀", + slackwebhookURL: "www.slack.com/webhook" + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("www.slack.com/webhook", { + + "channel": "chan", + "icon_emoji": "😀", + "text": "PassedInMessage😀", + "username": "name", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + setting.mockResolvedValueOnce("base.com"); + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Slack(); + + let notificationConf = { + type: "slack", + slackchannel: "chan", + slackusername: "name", + slackiconemo: "😀", + slackwebhookURL: "www.slack.com/webhook" + }; + let monitorConf = { + name: "testing monitor", + id: "123", + }; + let heartbeatConf = { + time: "test time" + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("www.slack.com/webhook", { + + "channel": "chan", + "icon_emoji": "😀", + "text": "PassedInMessage😀", + "username": "name", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + setting.mockResolvedValueOnce("base.com"); + + let notificationConf = { + type: "slack", + slackchannel: "chan", + slackusername: "name", + slackiconemo: "😀", + slackwebhookURL: "www.slack.com/webhook" + }; + let monitorConf = { + name: "testing monitor", + id: "123", + }; + let heartbeatConf = { + time: "test time" + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("www.slack.com/webhook", { + + "blocks": [ + { + "text": { + "text": "Uptime Kuma Alert", + "type": "plain_text", + }, + "type": "header", + }, + { + "fields": [ + { + "text": "*Message*\nPassedInMessage😀", + "type": "mrkdwn", + }, + { + "text": "*Time (UTC)*\ntest time", + "type": "mrkdwn", + }, + ], + "type": "section", + }, + { + "elements": [ + { + "text": { + "text": "Visit Uptime Kuma", + "type": "plain_text", + }, + "type": "button", + "url": "base.com/dashboard/123", + "value": "Uptime-Kuma", + }, + ], + "type": "actions", + }, + ], + "channel": "chan", + "icon_emoji": "😀", + "text": "Uptime Kuma Alert: testing monitor", + "username": "name", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/smtp.js b/server/notification-providers/smtp.js index 14429bc..31a0bc5 100644 --- a/server/notification-providers/smtp.js +++ b/server/notification-providers/smtp.js @@ -92,7 +92,7 @@ class SMTP extends NotificationProvider { text: bodyTextContent, }); - return "Sent Successfully."; + return this.sendSuccess; } } diff --git a/server/notification-providers/smtp.spec.js b/server/notification-providers/smtp.spec.js new file mode 100644 index 0000000..b3ffb42 --- /dev/null +++ b/server/notification-providers/smtp.spec.js @@ -0,0 +1,250 @@ +jest.mock("nodemailer", () => ({ + createTransport: jest.fn(), +})); +const mockNodeMailer = require("nodemailer"); +const { UP } = require("../../src/util"); +const NotificationSend = require("../notification"); + +const SMTP = require("./smtp"); + +beforeEach(() => { + mockNodeMailer.createTransport.mockReset(); +}); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new SMTP(); + expect(notification.name).toBe("smtp"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call transport with the proper default data", async () => { + let sender = jest.fn() + .mockResolvedValue(() => { + return; + }); + mockNodeMailer.createTransport.mockImplementationOnce(() => { + return { sendMail: sender }; + }); + + let notif = new SMTP(); + let notificationConf = { + smtpHost: "host", + smtpPort: "port", + smtpSecure: "secure", + smtpUsername: "username", + smtpPassword: "password", + customSubject: "", + smtpFrom: "From", + smtpCC: "CC", + smtpBCC: "BCC", + smtpTo: "To", + }; + let msg = "PassedInMessage"; + let monitorConf = { }; + let heartbeatConf = { }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(mockNodeMailer.createTransport).toHaveBeenCalledWith({ + auth: { + pass: "password", + user: "username", + }, + host: "host", + port: "port", + secure: "secure", + tls: { + "rejectUnauthorized": false, + } + }); + expect(res).toBe("Sent Successfully."); + expect(sender).toHaveBeenCalledWith({ + bcc: "BCC", + cc: "CC", + from: "From", + subject: "PassedInMessage", + text: "PassedInMessage\nTime (UTC): undefined", + + to: "To", + + }); + }); + + it("should use the proper email subject", async () => { + let sender = jest.fn() + .mockResolvedValue(() => { + return; + }); + mockNodeMailer.createTransport.mockImplementationOnce(() => { + return { sendMail: sender }; + }); + + let notif = new SMTP(); + let notificationConf = { + smtpHost: "host", + smtpPort: "port", + smtpSecure: "secure", + smtpUsername: "username", + smtpPassword: "password", + customSubject: "Name: {{NAME}} | Status: {{STATUS}} | Hostname: {{HOSTNAME_OR_URL}}", + smtpFrom: "From", + smtpCC: "CC", + smtpBCC: "BCC", + smtpTo: "To", + }; + let msg = "PassedInMessage"; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + + }; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(mockNodeMailer.createTransport).toHaveBeenCalledWith({ + auth: { + pass: "password", + user: "username", + }, + host: "host", + port: "port", + secure: "secure", + tls: { + "rejectUnauthorized": false, + } + }); + expect(res).toBe("Sent Successfully."); + expect(sender).toHaveBeenCalledWith({ + bcc: "BCC", + cc: "CC", + from: "From", + subject: "Name: testing | Status: ✅ Up | Hostname: https://www.google.com", + text: "PassedInMessage\nTime (UTC): undefined", + to: "To", + }); + }); +}); + +describe("notification to act properly on error from transport", () => { + it("should pass a createTransport error on", async () => { + let sender = jest.fn() + .mockResolvedValue(() => { + return; + }); + mockNodeMailer.createTransport.mockImplementationOnce(() => { + throw new Error("Test Error"); + }); + + let notif = new SMTP(); + let notificationConf = { }; + let msg = "PassedInMessage"; + let monitorConf = { }; + let heartbeatConf = { }; + let res = ""; + try { + res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(true).toBe(false); + } catch (e) { + expect(e.message).toBe("Test Error"); + } + + expect(mockNodeMailer.createTransport).toHaveBeenCalledTimes(1); + expect(res).toBe(""); + expect(sender).toHaveBeenCalledTimes(0); + }); + + it("should pass a send mail error on", async () => { + let sender = jest.fn() + .mockRejectedValue(new Error("Test Error")); + mockNodeMailer.createTransport.mockImplementationOnce(() => { + return { sendMail: sender }; + + }); + + let notif = new SMTP(); + let notificationConf = { }; + let msg = "PassedInMessage"; + let monitorConf = { }; + let heartbeatConf = { }; + let res = ""; + try { + res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + expect("threw error").toBe(false); + } catch (e) { + expect(e.message).toBe("Test Error"); + } + + expect(mockNodeMailer.createTransport).toHaveBeenCalledTimes(1); + expect(res).toBe(""); + expect(sender).toHaveBeenCalledTimes(1); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call sendMail with proper data", async () => { + let sender = jest.fn() + .mockResolvedValue(() => { + return; + }); + mockNodeMailer.createTransport.mockImplementationOnce(() => { + return { sendMail: sender }; + }); + + let notificationConf = { + type: "smtp", + smtpHost: "host", + smtpPort: "port", + smtpSecure: "secure", + smtpUsername: "username", + smtpPassword: "password", + customSubject: "", + smtpFrom: "From", + smtpCC: "CC", + smtpBCC: "BCC", + smtpTo: "To", + smtpIgnoreTLSError: true, + }; + let monitorConf = { + type: "http", + url: "https://www.google.com", + name: "testing", + }; + let heartbeatConf = { + status: UP, + }; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, "simple message", monitorConf, heartbeatConf); + + expect(res).toBe("Sent Successfully."); + + expect(mockNodeMailer.createTransport).toHaveBeenCalledTimes(1); + expect(mockNodeMailer.createTransport).toHaveBeenCalledWith({ + auth: { + pass: "password", + user: "username", + }, + host: "host", + port: "port", + secure: "secure", + tls: { + "rejectUnauthorized": true, + } + }); + expect(sender).toHaveBeenCalledTimes(1); + expect(sender).toHaveBeenCalledWith({ + bcc: "BCC", + cc: "CC", + from: "From", + subject: "simple message", + text: "simple message\nTime (UTC): undefined", + to: "To", + }); + }); + +}); diff --git a/server/notification-providers/teams.js b/server/notification-providers/teams.js index 859af56..edaa605 100644 --- a/server/notification-providers/teams.js +++ b/server/notification-providers/teams.js @@ -87,12 +87,11 @@ class Teams extends NotificationProvider { }; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { await this._handleGeneralNotification(notification.webhookUrl, msg); - return okMsg; + return this.sendSuccess; } let url; @@ -114,7 +113,7 @@ class Teams extends NotificationProvider { }); await this._sendNotification(notification.webhookUrl, payload); - return okMsg; + return this.sendSuccess; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/teams.spec.js b/server/notification-providers/teams.spec.js new file mode 100644 index 0000000..2f39ec9 --- /dev/null +++ b/server/notification-providers/teams.spec.js @@ -0,0 +1,283 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Teams = require("./teams"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Teams(); + expect(notification.name).toBe("teams"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data when up", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Teams(); + let notificationConf = { + webhookUrl: "teams.com/webhook" + }; + let monitorConf = { + type: "port", + hostname: "abc.com", + port: "1234", + url: "https://www.abc.com", + name: "name", + }; + let heartbeatConf = { + status: UP, + msg: "heart beating" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("teams.com/webhook", { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + "sections": [ + { + "activityImage": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "activityTitle": "**Uptime Kuma**", + }, + { + "activityTitle": "✅ Application [name] is back online", + }, + { + "activityTitle": "**Description**", + "facts": [ + { + "name": "Monitor", + "value": "name" + }, + { + "name": "URL", + "value": "abc.com:1234", + }, + ], + "text": "heart beating", + }, + ], + "summary": "✅ Application [name] is back online", + "themeColor": "00e804", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper default data when DOWN", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Teams(); + let notificationConf = { + webhookUrl: "teams.com/webhook" + }; + let monitorConf = { + type: "port", + hostname: "abc.com", + port: "1234", + url: "https://www.abc.com", + name: "name", + }; + let heartbeatConf = { + status: DOWN, + msg: "heart beating" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("teams.com/webhook", { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + "sections": [ + { + "activityImage": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "activityTitle": "**Uptime Kuma**", + }, + { + "activityTitle": "🔴 Application [name] went down", + }, + { + "activityTitle": "**Description**", + "facts": [ + { + "name": "Monitor", + "value": "name" + }, + { + "name": "URL", + "value": "abc.com:1234", + }, + ], + "text": "heart beating", + }, + ], + "summary": "🔴 Application [name] went down", + "themeColor": "ff0000", + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Teams(); + let notificationConf = { + webhookUrl: "teams.com/webhook" + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("teams.com/webhook", { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + "sections": [ + { + "activityImage": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "activityTitle": "**Uptime Kuma**", + }, + { + "activityTitle": "Notification", + }, + { + "activityTitle": "**Description**", + "facts": [ ], + "text": "PassedInMessage😀", + }, + ], + "summary": "Notification", + "themeColor": "008cff", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Teams(); + let notificationConf = { + webhookUrl: "teams.com/webhook" + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("teams.com/webhook", { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + "sections": [ + { + "activityImage": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "activityTitle": "**Uptime Kuma**", + }, + { + "activityTitle": "Notification", + }, + { + "activityTitle": "**Description**", + "facts": [ ], + "text": "PassedInMessage😀", + }, + ], + "summary": "Notification", + "themeColor": "008cff", + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "teams", + webhookUrl: "teams.com/webhook" + }; + let monitorConf = { + type: "port", + hostname: "abc.com", + port: "1234", + url: "https://www.abc.com", + name: "name", + }; + let heartbeatConf = { + status: DOWN, + msg: "heart beating" + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("teams.com/webhook", { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + "sections": [ + { + "activityImage": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "activityTitle": "**Uptime Kuma**", + }, + { + "activityTitle": "🔴 Application [name] went down", + }, + { + "activityTitle": "**Description**", + "facts": [ + { + "name": "Monitor", + "value": "name" + }, + { + "name": "URL", + "value": "abc.com:1234", + }, + ], + "text": "heart beating", + }, + ], + "summary": "🔴 Application [name] went down", + "themeColor": "ff0000", + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/telegram.js b/server/notification-providers/telegram.js index 54d33bf..4caef56 100644 --- a/server/notification-providers/telegram.js +++ b/server/notification-providers/telegram.js @@ -6,7 +6,6 @@ class Telegram extends NotificationProvider { name = "telegram"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, { @@ -14,12 +13,11 @@ class Telegram extends NotificationProvider { chat_id: notification.telegramChatID, text: msg, }, - }) - return okMsg; - + }); + return this.sendSuccess; } catch (error) { - let msg = (error.response.data.description) ? error.response.data.description : "Error without description" - throw new Error(msg) + let msg = (error.response.data.description) ? error.response.data.description : "Error without description"; + throw new Error(msg); } } } diff --git a/server/notification-providers/telegram.spec.js b/server/notification-providers/telegram.spec.js new file mode 100644 index 0000000..ef6e14d --- /dev/null +++ b/server/notification-providers/telegram.spec.js @@ -0,0 +1,155 @@ +jest.mock("axios", () => ({ + get: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.get.mockReset(); +}); +const Telegram = require("./telegram"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Telegram(); + expect(notification.name).toBe("telegram"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.get.mockResolvedValueOnce(response); + + let notif = new Telegram(); + let notificationConf = { + type: "telegram", + telegramBotToken: "abc", + telegramChatID: "123", + + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.get).toHaveBeenCalledWith("https://api.telegram.org/botabc/sendMessage", { + "params": { + "chat_id": "123", + "text": "PassedInMessage😀", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.get.mockResolvedValueOnce(response); + + let notif = new Telegram(); + let notificationConf = { + type: "telegram", + telegramBotToken: "abc", + telegramChatID: "123", + + }; + + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.get).toHaveBeenCalledWith("https://api.telegram.org/botabc/sendMessage", { + "params": { + "chat_id": "123", + "text": "PassedInMessage😀", + }, + }); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.get.mockImplementation(() => { + throw { + response: { + data: { + description: "Error Description" + } + } + }; + }); + let notif = new Telegram(); + let notificationConf = { + type: "telegram", + telegramBotToken: "abc", + telegramChatID: "123", + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error Description"); + } + + expect(axios.get).toHaveBeenCalledWith("https://api.telegram.org/botabc/sendMessage", { + "params": { + "chat_id": "123", + "text": "PassedInMessage😀", + }, + }); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.get.mockResolvedValueOnce(response); + let notificationConf = { + type: "telegram", + telegramBotToken: "abc", + telegramChatID: "123", + + }; + let monitorConf = { + }; + let heartbeatConf = { + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.get).toHaveBeenCalledWith("https://api.telegram.org/botabc/sendMessage", { + + "params": { + "chat_id": "123", + "text": "PassedInMessage😀", + }, + + }); + expect(res).toBe("Sent Successfully."); + }); + +}); diff --git a/server/notification-providers/webhook.js b/server/notification-providers/webhook.js index 9cb361f..1f7e368 100644 --- a/server/notification-providers/webhook.js +++ b/server/notification-providers/webhook.js @@ -7,7 +7,6 @@ class Webhook extends NotificationProvider { name = "webhook"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; try { let data = { @@ -24,17 +23,16 @@ class Webhook extends NotificationProvider { config = { headers: finalData.getHeaders(), - } + }; } else { finalData = data; } - await axios.post(notification.webhookURL, finalData, config) - return okMsg; - + await axios.post(notification.webhookURL, finalData, config); + return this.sendSuccess; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/webhook.spec.js b/server/notification-providers/webhook.spec.js new file mode 100644 index 0000000..232c436 --- /dev/null +++ b/server/notification-providers/webhook.spec.js @@ -0,0 +1,207 @@ +jest.mock("axios", () => ({ + post: jest.fn(), +})); + +const axios = require("axios"); +const { UP, DOWN } = require("../../src/util"); +const NotificationSend = require("../notification"); + +beforeEach(() => { + axios.post.mockReset(); +}); +const Webhook = require("./webhook"); + +describe("notification default information", () => { + it("should have the correct name", () => { + let notification = new Webhook(); + expect(notification.name).toBe("webhook"); + }); +}); + +describe("notification to act properly on send", () => { + it("should call axios with the proper default data as not form-data", async () => { + + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Webhook(); + let notificationConf = { + type: "webhook", + webhookURL: "abc.com/webhook", + webhookContentType: "JSON" + }; + let monitorConf = { + type: "port", + hostname: "abc.com", + port: "1234", + url: "https://www.abc.com", + name: "name", + }; + let heartbeatConf = { + status: DOWN, + msg: "heart beating" + }; + let msg = "PassedInMessage😀"; + let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + expect(axios.post).toHaveBeenCalledWith("abc.com/webhook", { + "heartbeat": { + "msg": "heart beating", + "status": 0, + }, + "monitor": { + "hostname": "abc.com", + "name": "name", + "port": "1234", + "type": "port", + "url": "https://www.abc.com", + }, + "msg": "PassedInMessage😀", + }, {}); + expect(res).toBe("Sent Successfully."); + }); + + //TODO finish headers test. + // it("should call axios with the proper default data as form-data", async () => { + + // let response = { + // data: { + // Message: "OK" + // } + // }; + // axios.post.mockResolvedValueOnce(response); + + // let notif = new Webhook(); + // let notificationConf = { + // type: "webhook", + // webhookURL: "abc.com/webhook", + // webhookContentType: "form-data" + // }; + // let monitorConf = { + // type: "port", + // hostname: "abc.com", + // port: "1234", + // url: "https://www.abc.com", + // name: "name", + // }; + // let heartbeatConf = { + // status: DOWN, + // msg: "heart beating" + // }; + // let msg = "PassedInMessage😀"; + // let res = await notif.send(notificationConf, msg, monitorConf, heartbeatConf); + + // expect(axios.post).toHaveBeenCalledWith("abc.com/webhook", {}, { + // "headers": { + // "content-type": "multipart/form-data; boundary=--------------------------219451039202311711580332", + // }, + // }); + // expect(res).toBe("Sent Successfully."); + // }); + + it("should call axios with the proper data when monitor nil", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + + let notif = new Webhook(); + let notificationConf = { + type: "webhook", + webhookURL: "abc.com/webhook" + }; + let msg = "PassedInMessage😀"; + + let res = await notif.send(notificationConf, msg, null, null); + + expect(axios.post).toHaveBeenCalledWith("abc.com/webhook", { + "heartbeat": null, + "monitor": null, + + "msg": "PassedInMessage😀", + }, {}); + expect(res).toBe("Sent Successfully."); + }); + +}); + +describe("notification to act properly on error", () => { + it("should respond with an axios error on error", async () => { + + axios.post.mockImplementation(() => { + throw new Error("Test Error"); + }); + let notif = new Webhook(); + let notificationConf = { + type: "webhook", + webhookURL: "abc.com/webhook" + }; + let msg = "PassedInMessage😀"; + + try { + await notif.send(notificationConf, msg, null, null); + expect("Error thrown").toBe(false); + } catch (e) { + expect(e.message).toBe("Error: Error: Test Error "); + } + + expect(axios.post).toHaveBeenCalledWith("abc.com/webhook", { + "heartbeat": null, + "monitor": null, + "msg": "PassedInMessage😀", + }, {}); + }); + +}); + +describe("notification to get proper data from Notification.send", () => { + it("should call axios with proper data", async () => { + let response = { + data: { + Message: "OK" + } + }; + axios.post.mockResolvedValueOnce(response); + let notificationConf = { + type: "webhook", + webhookURL: "abc.com/webhook" + }; + let monitorConf = { + type: "port", + hostname: "abc.com", + port: "1234", + url: "https://www.abc.com", + name: "name", + }; + let heartbeatConf = { + status: DOWN, + msg: "heart beating" + }; + let msg = "PassedInMessage😀"; + + NotificationSend.Notification.init(); + let res = await NotificationSend.Notification.send(notificationConf, msg, monitorConf, heartbeatConf); + expect(axios.post).toHaveBeenCalledWith("abc.com/webhook", { + "heartbeat": { + "msg": "heart beating", + "status": 0, + }, + "monitor": { + "hostname": "abc.com", + "name": "name", + "port": "1234", + "type": "port", + "url": "https://www.abc.com", + }, + "msg": "PassedInMessage😀", + }, {}); + expect(res).toBe("Sent Successfully."); + }); + +});