mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-02-12 12:29:20 -06:00
Merge pull request #932 from bluewave-labs/feat/be/invite-controller-tests
Feat/be/invite-controller-tests, #924
This commit is contained in:
@@ -8,17 +8,7 @@ require("dotenv").config();
|
||||
const jwt = require("jsonwebtoken");
|
||||
const { handleError, handleValidationError } = require("./controllerUtils");
|
||||
const SERVICE_NAME = "inviteController";
|
||||
|
||||
const getTokenFromHeaders = (headers) => {
|
||||
const authorizationHeader = headers.authorization;
|
||||
if (!authorizationHeader) throw new Error("No auth headers");
|
||||
|
||||
const parts = authorizationHeader.split(" ");
|
||||
if (parts.length !== 2 || parts[0] !== "Bearer")
|
||||
throw new Error("Invalid auth headers");
|
||||
|
||||
return parts[1];
|
||||
};
|
||||
const { getTokenFromHeaders } = require("../utils/utils");
|
||||
|
||||
/**
|
||||
* Issues an invitation to a new user. Only admins can invite new users. An invitation token is created and sent via email.
|
||||
@@ -93,6 +83,6 @@ const inviteVerifyController = async (req, res, next) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
inviteController: issueInvitation,
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ const { verifyJWT } = require("../middleware/verifyJWT");
|
||||
const { isAllowed } = require("../middleware/isAllowed");
|
||||
|
||||
const {
|
||||
inviteController,
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
} = require("../controllers/inviteController");
|
||||
|
||||
@@ -11,8 +11,8 @@ router.post(
|
||||
"/",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
verifyJWT,
|
||||
inviteController
|
||||
issueInvitation
|
||||
);
|
||||
router.post("/verify", inviteVerifyController);
|
||||
router.post("/verify", issueInvitation);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
202
Server/tests/controllers/inviteController.test.js
Normal file
202
Server/tests/controllers/inviteController.test.js
Normal file
@@ -0,0 +1,202 @@
|
||||
const {
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
} = require("../../controllers/inviteController");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const { errorMessages, successMessages } = require("../../utils/messages");
|
||||
const sinon = require("sinon");
|
||||
const joi = require("joi");
|
||||
describe("inviteController - issueInvitation", () => {
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: { authorization: "Bearer token" },
|
||||
body: {
|
||||
email: "test@test.com",
|
||||
role: ["admin"],
|
||||
teamId: "123",
|
||||
},
|
||||
db: { requestInviteToken: sinon.stub() },
|
||||
settingsService: { getSettings: sinon.stub() },
|
||||
emailService: { buildAndSendEmail: sinon.stub() },
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if role validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["bad_role"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(joi.ValidationError);
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.body = {};
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.db.requestInviteToken.throws(new Error("DB error"));
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should send an invite successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should send an email successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
|
||||
await issueInvitation(req, res, next);
|
||||
expect(req.emailService.buildAndSendEmail.calledOnce).to.be.true;
|
||||
expect(
|
||||
req.emailService.buildAndSendEmail.calledWith(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: "John",
|
||||
link: "http://localhost/register/inviteToken",
|
||||
},
|
||||
"test@test.com",
|
||||
"Welcome to Uptime Monitor"
|
||||
)
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should continue executing if sending an email fails", async () => {
|
||||
const token = "token";
|
||||
req.emailService.buildAndSendEmail.rejects(new Error("Email error"));
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("inviteController - inviteVerifyController", () => {
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: { token: "token" },
|
||||
db: {
|
||||
getInviteToken: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
req.body = {};
|
||||
await inviteVerifyController(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 an error if DB operations fail", async () => {
|
||||
req.db.getInviteToken.throws(new Error("DB error"));
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
|
||||
it("should return 200 and invite data when validation and invite retrieval are successful", async () => {
|
||||
req.db.getInviteToken.resolves({ invite: "data" });
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
status: "success",
|
||||
msg: "Invite verified",
|
||||
data: { invite: "data" },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.called).to.be.false;
|
||||
});
|
||||
});
|
||||
@@ -10,8 +10,8 @@ const { start } = require("repl");
|
||||
const roleValidatior = (role) => (value, helpers) => {
|
||||
const hasRole = role.some((role) => value.includes(role));
|
||||
if (!hasRole) {
|
||||
throw new Joi.ValidationError(
|
||||
`You do not have the required authorization. Required roles: ${roles.join(", ")}`
|
||||
throw new joi.ValidationError(
|
||||
`You do not have the required authorization. Required roles: ${role.join(", ")}`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
|
||||
Reference in New Issue
Block a user