generated from Real-Dev-Squad/website-template
-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for create onboarding extension request api (#2306)
* feat: added tests for middlewares * feat:added tests for controller * refactor: create middleware in beforeEach hook * refactor: remove requestBy field and super-users validation tests * fix: expectation message as test was failing * fix: change order of middleware creation as test was failing * fix: assert statement and mock value * feat: added tests for handling edges cases and fixed existing test * chore: correct test name * chore: fix lint issue
- Loading branch information
Showing
4 changed files
with
464 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
import addUser from "../utils/addUser"; | ||
import chai from "chai"; | ||
const { expect } = chai; | ||
import userDataFixture from "../fixtures/user/user"; | ||
import sinon from "sinon"; | ||
import chaiHttp from "chai-http"; | ||
import cleanDb from "../utils/cleanDb"; | ||
import { CreateOnboardingExtensionBody } from "../../types/onboardingExtension"; | ||
import { | ||
REQUEST_ALREADY_PENDING, | ||
REQUEST_STATE, REQUEST_TYPE, | ||
ONBOARDING_REQUEST_CREATED_SUCCESSFULLY, | ||
UNAUTHORIZED_TO_CREATE_ONBOARDING_EXTENSION_REQUEST | ||
} from "../../constants/requests"; | ||
const { generateToken } = require("../../test/utils/generateBotToken"); | ||
import app from "../../server"; | ||
import { createUserStatusWithState } from "../../utils/userStatus"; | ||
const firestore = require("../../utils/firestore"); | ||
const userStatusModel = firestore.collection("usersStatus"); | ||
import * as requestsQuery from "../../models/requests" | ||
import { userState } from "../../constants/userStatus"; | ||
const { CLOUDFLARE_WORKER, BAD_TOKEN } = require("../../constants/bot"); | ||
const userData = userDataFixture(); | ||
chai.use(chaiHttp); | ||
|
||
describe("/requests Onboarding Extension", () => { | ||
describe("POST /requests", () => { | ||
let testUserId: string; | ||
let testUserIdForInvalidDiscordJoinedDate: string; | ||
let testUserDiscordIdForInvalidDiscordJoinedDate: string = "54321"; | ||
|
||
const testUserDiscordId: string = "654321"; | ||
const extensionRequest = { | ||
state: REQUEST_STATE.APPROVED, | ||
type: REQUEST_TYPE.ONBOARDING, | ||
requestNumber: 1 | ||
}; | ||
const postEndpoint = "/requests"; | ||
const botToken = generateToken({name: CLOUDFLARE_WORKER}) | ||
const body: CreateOnboardingExtensionBody = { | ||
type: REQUEST_TYPE.ONBOARDING, | ||
numberOfDays: 5, | ||
reason: "This is the reason", | ||
userId: testUserDiscordId, | ||
}; | ||
|
||
beforeEach(async () => { | ||
testUserId = await addUser({ | ||
...userData[6], | ||
discordId: testUserDiscordId, | ||
discordJoinedAt: "2023-04-06T01:47:34.488000+00:00" | ||
}); | ||
testUserIdForInvalidDiscordJoinedDate = await addUser({ | ||
...userData[1], | ||
discordId: testUserDiscordIdForInvalidDiscordJoinedDate, | ||
discordJoinedAt: "2023-04-06T01" | ||
}); | ||
}); | ||
|
||
afterEach(async ()=>{ | ||
sinon.restore(); | ||
await cleanDb(); | ||
}) | ||
|
||
it("should not call verifyDiscordBot and return 401 response when extension type is not onboarding", (done)=> { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.send({...body, type: REQUEST_TYPE.OOO}) | ||
.end((err, res)=>{ | ||
if(err) return done(err); | ||
expect(res.statusCode).to.equal(401); | ||
expect(res.body.error).to.equal("Unauthorized"); | ||
expect(res.body.message).to.equal("Unauthenticated User"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return Feature not implemented when dev is not true", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}`) | ||
.send(body) | ||
.end((err, res)=>{ | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(501); | ||
expect(res.body.message).to.equal("Feature not implemented"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return Invalid Request when authorization header is missing", (done) => { | ||
chai | ||
.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", "") | ||
.send(body) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(400); | ||
expect(res.body.message).to.equal("Invalid Request"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return Unauthorized Bot for invalid token", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${BAD_TOKEN}`) | ||
.send(body) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(401); | ||
expect(res.body.message).to.equal("Unauthorized Bot"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 400 response for invalid value type of numberOfDays", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send({...body, numberOfDays:"1"}) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(400); | ||
expect(res.body.message).to.equal("numberOfDays must be a number"); | ||
expect(res.body.error).to.equal("Bad Request"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 400 response for invalid value of numberOfDays", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send({...body, numberOfDays:1.4}) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(400); | ||
expect(res.body.message).to.equal("numberOfDays must be a integer"); | ||
expect(res.body.error).to.equal("Bad Request"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 400 response for invalid userId", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send({...body, userId: undefined}) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(400); | ||
expect(res.body.message).to.equal("userId is required"); | ||
expect(res.body.error).to.equal("Bad Request"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 500 response when fails to create extension request", (done) => { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ONBOARDING); | ||
sinon.stub(requestsQuery, "createRequest") | ||
.throws("Error while creating extension request"); | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body) | ||
.end((err, res)=>{ | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(500); | ||
expect(res.body.message).to.equal("An internal server error occurred"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 500 response when discordJoinedAt date string is invalid", (done) => { | ||
createUserStatusWithState(testUserIdForInvalidDiscordJoinedDate, userStatusModel, userState.ONBOARDING); | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send({...body, userId: testUserDiscordIdForInvalidDiscordJoinedDate}) | ||
.end((err, res)=>{ | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(500); | ||
expect(res.body.message).to.equal("An internal server error occurred"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 404 response when user does not exist", (done) => { | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send({...body, userId: "11111"}) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(404); | ||
expect(res.body.error).to.equal("Not Found"); | ||
expect(res.body.message).to.equal("User not found"); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 403 response when user's status is not onboarding", (done)=> { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ACTIVE); | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(403); | ||
expect(res.body.error).to.equal("Forbidden"); | ||
expect(res.body.message).to.equal(UNAUTHORIZED_TO_CREATE_ONBOARDING_EXTENSION_REQUEST); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 400 response when a user already has a pending request", (done)=> { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ONBOARDING); | ||
requestsQuery.createRequest({...extensionRequest, state: REQUEST_STATE.PENDING, userId: testUserId}); | ||
|
||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(400); | ||
expect(res.body.error).to.equal("Bad Request"); | ||
expect(res.body.message).to.equal(REQUEST_ALREADY_PENDING); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 201 for successful response when user has onboarding state", (done)=> { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ONBOARDING); | ||
chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body) | ||
.end((err, res) => { | ||
if (err) return done(err); | ||
expect(res.statusCode).to.equal(201); | ||
expect(res.body.message).to.equal(ONBOARDING_REQUEST_CREATED_SUCCESSFULLY); | ||
expect(res.body.data.requestNumber).to.equal(1); | ||
expect(res.body.data.reason).to.equal(body.reason); | ||
expect(res.body.data.state).to.equal(REQUEST_STATE.PENDING); | ||
done(); | ||
}) | ||
}) | ||
|
||
it("should return 201 response when previous latest extension request is approved", async () => { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ONBOARDING); | ||
const latestApprovedExtension = await requestsQuery.createRequest({ | ||
...extensionRequest, | ||
userId: testUserId, | ||
state: REQUEST_STATE.APPROVED, | ||
newEndsOn: Date.now() + 2*24*60*60*1000, | ||
oldEndsOn: Date.now() - 24*60*60*1000, | ||
}); | ||
|
||
const res = await chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body); | ||
|
||
expect(res.statusCode).to.equal(201); | ||
expect(res.body.message).to.equal(ONBOARDING_REQUEST_CREATED_SUCCESSFULLY); | ||
expect(res.body.data.requestNumber).to.equal(2); | ||
expect(res.body.data.reason).to.equal(body.reason); | ||
expect(res.body.data.state).to.equal(REQUEST_STATE.PENDING); | ||
expect(res.body.data.oldEndsOn).to.equal(latestApprovedExtension.newEndsOn); | ||
expect(res.body.data.newEndsOn).to.equal(latestApprovedExtension.newEndsOn + (body.numberOfDays*24*60*60*1000)); | ||
}) | ||
|
||
it("should return 201 response when previous latest extension request is rejected", async () => { | ||
createUserStatusWithState(testUserId, userStatusModel, userState.ONBOARDING); | ||
const currentDate = Date.now(); | ||
const latestRejectedExtension = await requestsQuery.createRequest({ | ||
...extensionRequest, | ||
state: REQUEST_STATE.REJECTED, | ||
userId: testUserId, | ||
newEndsOn: currentDate, | ||
oldEndsOn: currentDate - 24*60*60*1000, | ||
}); | ||
|
||
const res = await chai.request(app) | ||
.post(`${postEndpoint}?dev=true`) | ||
.set("authorization", `Bearer ${botToken}`) | ||
.send(body); | ||
|
||
expect(res.statusCode).to.equal(201); | ||
expect(res.body.message).to.equal(ONBOARDING_REQUEST_CREATED_SUCCESSFULLY); | ||
expect(res.body.data.requestNumber).to.equal(2); | ||
expect(res.body.data.reason).to.equal(body.reason);; | ||
expect(res.body.data.state).to.equal(REQUEST_STATE.PENDING); | ||
expect(res.body.data.oldEndsOn).to.equal(latestRejectedExtension.oldEndsOn); | ||
expect(new Date(res.body.data.newEndsOn).toDateString()) | ||
.to.equal(new Date(currentDate + (body.numberOfDays*24*60*60*1000)).toDateString()); | ||
}) | ||
}) | ||
}); |
70 changes: 70 additions & 0 deletions
70
test/unit/middlewares/onboardingExtensionRequestValidator.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { REQUEST_TYPE } from "../../../constants/requests"; | ||
import { createOnboardingExtensionRequestValidator } from "../../../middlewares/validators/onboardingExtensionRequest"; | ||
import sinon from "sinon"; | ||
import { CreateOnboardingExtensionBody } from "../../../types/onboardingExtension"; | ||
import { expect } from "chai"; | ||
|
||
describe("Onboarding Extension Request Validators", () => { | ||
let req: any; | ||
let res: any; | ||
let nextSpy: sinon.SinonSpy; | ||
beforeEach(function () { | ||
res = { | ||
boom: { | ||
badRequest: sinon.spy(), | ||
}, | ||
}; | ||
nextSpy = sinon.spy(); | ||
}); | ||
|
||
describe("createOnboardingExtensionRequestValidator", () => { | ||
const requestBody:CreateOnboardingExtensionBody = { | ||
numberOfDays: 1, | ||
reason: "This is reason", | ||
userId: "22222", | ||
type: REQUEST_TYPE.ONBOARDING | ||
} | ||
it("should validate for a valid create request", async () => { | ||
req = { | ||
body: requestBody | ||
}; | ||
res = {}; | ||
|
||
await createOnboardingExtensionRequestValidator(req as any, res as any, nextSpy); | ||
expect(nextSpy.calledOnce, "next should be called once"); | ||
}); | ||
|
||
it("should not validate for an invalid request on wrong type", async () => { | ||
req = { | ||
body: { ...requestBody, type: REQUEST_TYPE.EXTENSION }, | ||
}; | ||
try { | ||
await createOnboardingExtensionRequestValidator(req as any, res as any, nextSpy); | ||
} catch (error) { | ||
expect(error.details[0].message).to.equal(`"type" must be [ONBOARDING]`); | ||
} | ||
}); | ||
|
||
it("should not validate for an invalid request on wrong numberOfDays", async () => { | ||
req = { | ||
body: { ...requestBody, numberOfDays: "2" }, | ||
}; | ||
try { | ||
await createOnboardingExtensionRequestValidator(req as any, res as any, nextSpy); | ||
} catch (error) { | ||
expect(error.details[0].message).to.equal(`numberOfDays must be a number`); | ||
} | ||
}); | ||
|
||
it("should not validate for an invalid request on wrong userId", async () => { | ||
req = { | ||
body: { ...requestBody, userId: undefined }, | ||
}; | ||
try { | ||
await createOnboardingExtensionRequestValidator(req as any, res as any, nextSpy); | ||
} catch (error) { | ||
expect(error.details[0].message).to.equal(`userId is required`); | ||
} | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.