From 22a6d2ef2c32efbb82b9019d9bda574078f12ad8 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 10:39:18 +0800 Subject: [PATCH 1/7] Add creatCheck test --- Server/.mocharc.js | 2 +- Server/controllers/checkController.js | 1 + .../tests/controllers/checkController.test.js | 63 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Server/tests/controllers/checkController.test.js diff --git a/Server/.mocharc.js b/Server/.mocharc.js index 5c8840544..87f578c2e 100644 --- a/Server/.mocharc.js +++ b/Server/.mocharc.js @@ -1,6 +1,6 @@ module.exports = { require: ["chai/register-expect.js"], // Include Chai's "expect" interface globally - spec: "tests/**/*.test.js", // Specify test files + // spec: "tests/**/*.test.js", // Specify test files timeout: 5000, // Set test-case timeout in milliseconds recursive: true, // Include subdirectories reporter: "spec", // Use the "spec" reporter diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index b0e98ed38..130509b1e 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -20,6 +20,7 @@ const createCheck = async (req, res, next) => { await createCheckParamValidation.validateAsync(req.params); await createCheckBodyValidation.validateAsync(req.body); } catch (error) { + console.log(error); next(handleValidationError(error, SERVICE_NAME)); return; } diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js new file mode 100644 index 000000000..43f431df2 --- /dev/null +++ b/Server/tests/controllers/checkController.test.js @@ -0,0 +1,63 @@ +const { createCheck } = require("../../controllers/checkController"); +const jwt = require("jsonwebtoken"); +const { errorMessages, successMessages } = require("../../utils/messages"); +const sinon = require("sinon"); + +describe("Check Controller - createCheck", () => { + beforeEach(() => { + req = { + params: {}, + body: {}, + db: { + createCheck: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + handleError = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); // Restore the original methods after each test + }); + + it("should reject with a validation if params are invalid", async () => { + await createCheck(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should reject with a validation error if body is invalid", async () => { + req.params = { + monitorId: "monitorId", + }; + await createCheck(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + }); + it("should return a success message if check is created", async () => { + req.params = { + monitorId: "monitorId", + }; + req.db.createCheck.resolves({ id: "123" }); + req.body = { + monitorId: "monitorId", + status: true, + responseTime: 100, + statusCode: 200, + message: "message", + }; + await createCheck(req, res, next); + expect(res.status.calledWith(200)).to.be.true; + expect( + res.json.calledWith({ + success: true, + msg: successMessages.CHECK_CREATE, + data: { id: "123" }, + }) + ).to.be.true; + expect(next.notCalled).to.be.true; + }); +}); From 9eb06a477f4964f1b39f5212088e9e4ea4841b97 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 10:49:44 +0800 Subject: [PATCH 2/7] Add tests for getChecks --- Server/controllers/checkController.js | 1 - .../tests/controllers/checkController.test.js | 57 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index 130509b1e..b0e98ed38 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -20,7 +20,6 @@ const createCheck = async (req, res, next) => { await createCheckParamValidation.validateAsync(req.params); await createCheckBodyValidation.validateAsync(req.body); } catch (error) { - console.log(error); next(handleValidationError(error, SERVICE_NAME)); return; } diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js index 43f431df2..8b8ecbfcd 100644 --- a/Server/tests/controllers/checkController.test.js +++ b/Server/tests/controllers/checkController.test.js @@ -1,4 +1,4 @@ -const { createCheck } = require("../../controllers/checkController"); +const { createCheck, getChecks } = require("../../controllers/checkController"); const jwt = require("jsonwebtoken"); const { errorMessages, successMessages } = require("../../utils/messages"); const sinon = require("sinon"); @@ -61,3 +61,58 @@ describe("Check Controller - createCheck", () => { expect(next.notCalled).to.be.true; }); }); + +describe("Check Controller - getChecks", () => { + beforeEach(() => { + req = { + params: {}, + query: {}, + db: { + getChecks: sinon.stub(), + getChecksCount: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should reject with a validation error if params are invalid", async () => { + await getChecks(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should return a success message if checks are found", async () => { + req.params = { + monitorId: "monitorId", + }; + req.db.getChecks.resolves([{ id: "123" }]); + req.db.getChecksCount.resolves(1); + await getChecks(req, res, next); + expect(res.status.calledWith(200)).to.be.true; + expect( + res.json.calledWith({ + success: true, + msg: successMessages.CHECK_GET, + data: { checksCount: 1, checks: [{ id: "123" }] }, + }) + ).to.be.true; + expect(next.notCalled).to.be.true; + }); + + it("should handle errors", async () => { + req.db.getChecks.rejects(new Error("error")); + await getChecks(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + req.db.getChecks.resolves([]); + req.db.getChecksCount.rejects(new Error("error")); + await getChecks(req, res, next); + }); +}); From 4276f92bd43071334ffed1b24af18868128a5b0d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 10:56:35 +0800 Subject: [PATCH 3/7] Add tests for getTeamChecks --- .../tests/controllers/checkController.test.js | 62 ++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js index 8b8ecbfcd..8f6153d23 100644 --- a/Server/tests/controllers/checkController.test.js +++ b/Server/tests/controllers/checkController.test.js @@ -1,4 +1,8 @@ -const { createCheck, getChecks } = require("../../controllers/checkController"); +const { + createCheck, + getChecks, + getTeamChecks, +} = require("../../controllers/checkController"); const jwt = require("jsonwebtoken"); const { errorMessages, successMessages } = require("../../utils/messages"); const sinon = require("sinon"); @@ -107,7 +111,7 @@ describe("Check Controller - getChecks", () => { expect(next.notCalled).to.be.true; }); - it("should handle errors", async () => { + it("should call next with error if data retrieval fails", async () => { req.db.getChecks.rejects(new Error("error")); await getChecks(req, res, next); expect(next.firstCall.args[0]).to.be.an("error"); @@ -116,3 +120,57 @@ describe("Check Controller - getChecks", () => { await getChecks(req, res, next); }); }); + +describe("Check Controller - getTeamChecks", () => { + beforeEach(() => { + req = { + params: {}, + query: {}, + db: { + getTeamChecks: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should reject with a validation error if params are invalid", async () => { + await getTeamChecks(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should return 200 and check data on successful validation and data retrieval", async () => { + req.params = { teamId: "1" }; + const checkData = [{ id: 1, name: "Check 1" }]; + req.db.getTeamChecks.resolves(checkData); + + await getTeamChecks(req, res, next); + expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true; + expect(res.status.calledOnceWith(200)).to.be.true; + expect( + res.json.calledOnceWith({ + success: true, + msg: successMessages.CHECK_GET, + data: checkData, + }) + ).to.be.true; + }); + + it("should call next with error if data retrieval fails", async () => { + req.params = { teamId: "1" }; + req.db.getTeamChecks.rejects(new Error("Retrieval Error")); + await getTeamChecks(req, res, next); + expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true; + expect(next.firstCall.args[0]).to.be.an("error"); + expect(res.status.notCalled).to.be.true; + expect(res.json.notCalled).to.be.true; + }); +}); From 14ce25dbc75273877cfc85b6d9891c4b6c428248 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 11:00:17 +0800 Subject: [PATCH 4/7] Add tests for deleteChecks --- .../tests/controllers/checkController.test.js | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js index 8f6153d23..6a7c74354 100644 --- a/Server/tests/controllers/checkController.test.js +++ b/Server/tests/controllers/checkController.test.js @@ -2,6 +2,8 @@ const { createCheck, getChecks, getTeamChecks, + deleteChecks, + deleteChecksByTeamId, } = require("../../controllers/checkController"); const jwt = require("jsonwebtoken"); const { errorMessages, successMessages } = require("../../utils/messages"); @@ -174,3 +176,54 @@ describe("Check Controller - getTeamChecks", () => { expect(res.json.notCalled).to.be.true; }); }); + +describe("Check Controller - deleteChecks", () => { + beforeEach(() => { + req = { + params: {}, + db: { + deleteChecks: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should reject with an error if param validation fails", async () => { + await deleteChecks(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should call next with error if data retrieval fails", async () => { + req.params = { monitorId: "1" }; + req.db.deleteChecks.rejects(new Error("Deletion Error")); + await deleteChecks(req, res, next); + expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true; + expect(next.firstCall.args[0]).to.be.an("error"); + expect(res.status.notCalled).to.be.true; + expect(res.json.notCalled).to.be.true; + }); + + it("should delete checks successfully", async () => { + req.params = { monitorId: "123" }; + req.db.deleteChecks.resolves(1); + await deleteChecks(req, res, next); + expect(req.db.deleteChecks.calledOnceWith("123")).to.be.true; + expect(res.status.calledOnceWith(200)).to.be.true; + expect( + res.json.calledOnceWith({ + success: true, + msg: successMessages.CHECK_DELETE, + data: { deletedCount: 1 }, + }) + ).to.be.true; + }); +}); From ab4cf69222440de7d4df36aa68bb10c62f559710 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 11:34:05 +0800 Subject: [PATCH 5/7] Add tests for updateCheckTTL --- .../tests/controllers/checkController.test.js | 125 +++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js index 6a7c74354..d71bd807c 100644 --- a/Server/tests/controllers/checkController.test.js +++ b/Server/tests/controllers/checkController.test.js @@ -4,6 +4,7 @@ const { getTeamChecks, deleteChecks, deleteChecksByTeamId, + updateChecksTTL, } = require("../../controllers/checkController"); const jwt = require("jsonwebtoken"); const { errorMessages, successMessages } = require("../../utils/messages"); @@ -216,7 +217,7 @@ describe("Check Controller - deleteChecks", () => { req.params = { monitorId: "123" }; req.db.deleteChecks.resolves(1); await deleteChecks(req, res, next); - expect(req.db.deleteChecks.calledOnceWith("123")).to.be.true; + expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true; expect(res.status.calledOnceWith(200)).to.be.true; expect( res.json.calledOnceWith({ @@ -227,3 +228,125 @@ describe("Check Controller - deleteChecks", () => { ).to.be.true; }); }); + +describe("Check Controller - deleteChecksByTeamId", () => { + beforeEach(() => { + req = { + params: {}, + db: { + deleteChecksByTeamId: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should reject with an error if param validation fails", async () => { + await deleteChecksByTeamId(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should call next with error if data retrieval fails", async () => { + req.params = { teamId: "1" }; + req.db.deleteChecksByTeamId.rejects(new Error("Deletion Error")); + await deleteChecksByTeamId(req, res, next); + expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be + .true; + expect(next.firstCall.args[0]).to.be.an("error"); + expect(res.status.notCalled).to.be.true; + expect(res.json.notCalled).to.be.true; + }); + + it("should delete checks successfully", async () => { + req.params = { teamId: "123" }; + req.db.deleteChecksByTeamId.resolves(1); + await deleteChecksByTeamId(req, res, next); + expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be + .true; + expect(res.status.calledOnceWith(200)).to.be.true; + expect( + res.json.calledOnceWith({ + success: true, + msg: successMessages.CHECK_DELETE, + data: { deletedCount: 1 }, + }) + ).to.be.true; + }); +}); + +describe("Check Controller - updateCheckTTL", () => { + beforeEach(() => { + stub = sinon.stub(jwt, "verify").callsFake(() => { + return { teamId: "123" }; + }); + + req = { + body: {}, + headers: { authorization: "Bearer token" }, + settingsService: { + getSettings: sinon.stub().returns({ jwtSecret: "my_secret" }), + }, + db: { + updateChecksTTL: sinon.stub(), + }, + }; + res = { + status: sinon.stub().returnsThis(), + json: sinon.stub(), + }; + next = sinon.stub(); + }); + + afterEach(() => { + sinon.restore(); + stub.restore(); + }); + + it("should reject if body validation fails", async () => { + await updateChecksTTL(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); + }); + + it("should throw a JwtError if verification fails", async () => { + stub.restore(); + req.body = { + ttl: 1, + }; + await updateChecksTTL(req, res, next); + expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError); + }); + + it("should call next with error if data retrieval fails", async () => { + req.body = { + ttl: 1, + }; + req.db.updateChecksTTL.rejects(new Error("Update Error")); + await updateChecksTTL(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + }); + + it("should update TTL successfully", async () => { + req.body = { + ttl: 1, + }; + req.db.updateChecksTTL.resolves(); + await updateChecksTTL(req, res, next); + expect(req.db.updateChecksTTL.calledOnceWith("123", 1 * 86400)).to.be.true; + expect(res.status.calledOnceWith(200)).to.be.true; + expect( + res.json.calledOnceWith({ + success: true, + msg: successMessages.CHECK_UPDATE_TTL, + }) + ).to.be.true; + }); +}); From 150b4c6f0fc9a3a302a007bdcd3af26529c9670d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 11:40:10 +0800 Subject: [PATCH 6/7] Add missing tests for 100% coverage --- Server/.mocharc.js | 2 +- Server/controllers/checkController.js | 1 + .../tests/controllers/checkController.test.js | 24 ++++++++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Server/.mocharc.js b/Server/.mocharc.js index 87f578c2e..5c8840544 100644 --- a/Server/.mocharc.js +++ b/Server/.mocharc.js @@ -1,6 +1,6 @@ module.exports = { require: ["chai/register-expect.js"], // Include Chai's "expect" interface globally - // spec: "tests/**/*.test.js", // Specify test files + spec: "tests/**/*.test.js", // Specify test files timeout: 5000, // Set test-case timeout in milliseconds recursive: true, // Include subdirectories reporter: "spec", // Use the "spec" reporter diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index b0e98ed38..be09d795b 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -31,6 +31,7 @@ const createCheck = async (req, res, next) => { .status(200) .json({ success: true, msg: successMessages.CHECK_CREATE, data: check }); } catch (error) { + console.log(error); next(handleError(error, SERVICE_NAME, "createCheck")); } }; diff --git a/Server/tests/controllers/checkController.test.js b/Server/tests/controllers/checkController.test.js index d71bd807c..a3060d60a 100644 --- a/Server/tests/controllers/checkController.test.js +++ b/Server/tests/controllers/checkController.test.js @@ -43,7 +43,25 @@ describe("Check Controller - createCheck", () => { }; await createCheck(req, res, next); expect(next.firstCall.args[0]).to.be.an("error"); + expect(next.firstCall.args[0].status).to.equal(422); }); + + it("should call next with error if data retrieval fails", async () => { + req.params = { + monitorId: "monitorId", + }; + req.body = { + monitorId: "monitorId", + status: true, + responseTime: 100, + statusCode: 200, + message: "message", + }; + req.db.createCheck.rejects(new Error("error")); + await createCheck(req, res, next); + expect(next.firstCall.args[0]).to.be.an("error"); + }); + it("should return a success message if check is created", async () => { req.params = { monitorId: "monitorId", @@ -115,12 +133,12 @@ describe("Check Controller - getChecks", () => { }); it("should call next with error if data retrieval fails", async () => { + req.params = { + monitorId: "monitorId", + }; req.db.getChecks.rejects(new Error("error")); await getChecks(req, res, next); expect(next.firstCall.args[0]).to.be.an("error"); - req.db.getChecks.resolves([]); - req.db.getChecksCount.rejects(new Error("error")); - await getChecks(req, res, next); }); }); From 0a805c1383f605beaff00b12a9d406e4c5d35516 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Oct 2024 11:40:35 +0800 Subject: [PATCH 7/7] Remove console log --- Server/controllers/checkController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index be09d795b..b0e98ed38 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -31,7 +31,6 @@ const createCheck = async (req, res, next) => { .status(200) .json({ success: true, msg: successMessages.CHECK_CREATE, data: check }); } catch (error) { - console.log(error); next(handleError(error, SERVICE_NAME, "createCheck")); } };