-
Notifications
You must be signed in to change notification settings - Fork 204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/be/invite-controller-tests, #924 #932
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,16 +3,16 @@ const { verifyJWT } = require("../middleware/verifyJWT"); | |
const { isAllowed } = require("../middleware/isAllowed"); | ||
|
||
const { | ||
inviteController, | ||
issueInvitation, | ||
inviteVerifyController, | ||
} = require("../controllers/inviteController"); | ||
|
||
router.post( | ||
"/", | ||
isAllowed(["admin", "superadmin"]), | ||
verifyJWT, | ||
inviteController | ||
issueInvitation | ||
); | ||
router.post("/verify", inviteVerifyController); | ||
router.post("/verify", issueInvitation); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yo, hold up! Something's fishy here, and it ain't mom's spaghetti. I'm sweating bullets here, 'cause this line's got me shook. We're using Shouldn't we be using Can you double-check if this is intentional or if we need to swap in |
||
|
||
module.exports = router; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" }, | ||
Check failure Code scanning / CodeQL Hard-coded credentials Critical test
The hard-coded value "Bearer token" is used as
authorization header Error loading related location Loading There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hold up, we got a security issue here! Yo, I'm sweatin' bullets over here 'cause we got a hard-coded token in the authorization header. That's a no-go, my friend. We gotta keep it real and keep it secure. Let's swap out that hard-coded "Bearer token" with a dynamic token generation. Something like: authorization: `Bearer ${generateTestToken()}` Don't forget to implement that 🧰 Tools🪛 GitHub Check: CodeQL
|
||
body: { | ||
email: "[email protected]", | ||
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", | ||
}, | ||
"[email protected]", | ||
"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; | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Whoa, 'inviteController' is still hanging around in a few places! Let's tidy this up to keep things smooth.
Server/tests/controllers/inviteController.test.js
Server/controllers/inviteController.js
🔗 Analysis chain
Yo, this change is fire! But let's make sure we ain't trippin'.
The import change from
inviteController
toissueInvitation
is on point, making the code clearer. It's like mom's spaghetti - simple but effective.Let's double-check if we missed any spots where
inviteController
was used:🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 567