Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions models/impersonationRequests.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import firestore from "../utils/firestore";
import {
ERROR_WHILE_CREATING_REQUEST,
IMPERSONATION_NOT_COMPLETED,
REQUEST_ALREADY_PENDING,
REQUEST_STATE,
ERROR_WHILE_FETCHING_REQUEST
} from "../constants/requests";
import { Timestamp } from "firebase-admin/firestore";
Expand Down
48 changes: 47 additions & 1 deletion test/unit/middlewares/impersonationRequests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import {
createImpersonationRequestValidator,
getImpersonationRequestByIdValidator,
getImpersonationRequestsValidator
getImpersonationRequestsValidator,
updateImpersonationRequestValidator

Check failure on line 7 in test/unit/middlewares/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

'"../../../middlewares/validators/impersonationRequests"' has no exported member named 'updateImpersonationRequestValidator'. Did you mean 'createImpersonationRequestValidator'?
} from "../../../middlewares/validators/impersonationRequests";
import {
CreateImpersonationRequest,
CreateImpersonationRequestBody,
ImpersonationRequestResponse,
GetImpersonationControllerRequest,
GetImpersonationRequestByIdRequest,
UpdateImpersonationRequest,

Check failure on line 15 in test/unit/middlewares/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

'"../../../types/impersonationRequest"' has no exported member named 'UpdateImpersonationRequest'. Did you mean 'ImpersonationRequest'?
UpdateImpersonationRequestStatusBody,
} from "../../../types/impersonationRequest";
import { Request, Response } from "express";
import { getImpersonationRequestById } from "../../../models/impersonationRequests";
Expand All @@ -28,6 +31,11 @@
reason: "Testing purpose",
};

const updateRequestBody: UpdateImpersonationRequestStatusBody = {
status: "APPROVED",
message: "Testing",
};

beforeEach(function () {
res = {
boom: {
Expand Down Expand Up @@ -177,4 +185,42 @@
expect(nextSpy.called).to.be.false;
});
});

describe("updateImpersonationRequestValidator", function () {
it("should validate for a valid update impersonation request", async function () {
req = {
body: updateRequestBody,
};
await updateImpersonationRequestValidator(
req as UpdateImpersonationRequest,
res as ImpersonationRequestResponse,
nextSpy
);
expect(nextSpy.calledOnce).to.be.true;
});

it("should not validate for an invalid update impersonation request on missing status", async function () {
req = {
body: { ...updateRequestBody, status: "" },
};
await updateImpersonationRequestValidator(
req as UpdateImpersonationRequest,
res as ImpersonationRequestResponse,
nextSpy
);
expect(res.boom.badRequest.calledOnce).to.be.true;
expect(nextSpy.called).to.be.false;
});

it("should invalidate if status field is not of correct type", async function () {
req = {
body: { ...updateRequestBody, status: "ACTIVE" },
};
await updateImpersonationRequestValidator(req as UpdateImpersonationRequest,res as ImpersonationRequestResponse, nextSpy);
const errorMessageArg = res.boom.badRequest.firstCall.args[0];
expect(res.boom.badRequest.calledOnce).to.be.true;
expect(errorMessageArg).to.include("status must be APPROVED or REJECTED");
expect(nextSpy.called).to.be.false;
});
});
});
100 changes: 89 additions & 11 deletions test/unit/models/impersonationRequests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
import cleanDb from "../../utils/cleanDb";
import * as impersonationModel from "../../../models/impersonationRequests";
import { impersonationRequestsBodyData } from "../../fixtures/impersonation-requests/impersonationRequests";
import { REQUEST_STATE, ERROR_WHILE_CREATING_REQUEST } from "../../../constants/requests";
import { REQUEST_STATE, ERROR_WHILE_CREATING_REQUEST, ERROR_WHILE_UPDATING_REQUEST } from "../../../constants/requests";
import addUser from "../../utils/addUser";
import userDataFixture from "../../fixtures/user/user";
import sinon from "sinon";
import { UpdateImpersonationRequestStatusBody, UpdateImpersonationRequestDataResponse } from "../../../types/impersonationRequest";

Check failure on line 9 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

'"../../../types/impersonationRequest"' has no exported member named 'UpdateImpersonationRequestDataResponse'. Did you mean 'UpdateImpersonationRequestDataBody'?
import { Timestamp } from "firebase-admin/firestore";
import firestore from "../../../utils/firestore";


const userData = userDataFixture();
const logger = require("../../../utils/logger");

describe("models/impersonationRequests", () => {
let impersonationRequest;
Expand All @@ -26,7 +30,7 @@
await cleanDb();
});

describe("createImpersonationRequest", () => {
describe("createImpersonationRequest", () => {
it("should create a new impersonation request", async () => {
impersonationRequest = await impersonationModel.createImpersonationRequest(mockRequestBody);
expect(impersonationRequest).to.have.property("id");
Expand All @@ -39,7 +43,7 @@
});

it("should throw an error if there is an existing PENDING impersonation request", async () => {
await impersonationModel.createImpersonationRequest(mockRequestBody);
await impersonationModel.createImpersonationRequest(mockRequestBody);
try {
await impersonationModel.createImpersonationRequest(mockRequestBody);
} catch (error) {
Expand All @@ -48,8 +52,8 @@
});

it("should allow different super users to create requests for same user", async () => {
const request1 = await impersonationModel.createImpersonationRequest({ ...impersonationRequestsBodyData[0],createdBy: "user1" });
const request2 = await impersonationModel.createImpersonationRequest({ ...impersonationRequestsBodyData[0],createdBy: "user2", userId:"122" });
const request1 = await impersonationModel.createImpersonationRequest({ ...impersonationRequestsBodyData[0], createdBy: "user1" });
const request2 = await impersonationModel.createImpersonationRequest({ ...impersonationRequestsBodyData[0], createdBy: "user2", userId: "122" });
expect(request1).to.have.property("id");
expect(request1.createdBy).to.equal("user1");
expect(request1.impersonatedUserId).to.equal(impersonationRequestsBodyData[0].impersonatedUserId);
Expand All @@ -69,16 +73,15 @@
}
});

it("should throw forbidden error if an APPROVED request with isImpersonationFinished as false is present", async ()=>{
it("should throw forbidden error if an APPROVED request with isImpersonationFinished as false is present", async () => {
try {
await impersonationModel.createImpersonationRequest({...impersonationRequestsBodyData[0],status:REQUEST_STATE.APPROVED});
await impersonationModel.createImpersonationRequest({ ...impersonationRequestsBodyData[0], status: REQUEST_STATE.APPROVED });
await impersonationModel.createImpersonationRequest(impersonationRequestsBodyData[0]);
} catch (error) {
expect(error.message).to.include("You are not allowed for this Operation at the moment");
}
})
});

});
});
describe("getImpersonationRequestById", () => {
it("should return the impersonation request by id", async () => {
const impersonationRequest = await impersonationModel.createImpersonationRequest(impersonationRequestsBodyData[0]);
Expand Down Expand Up @@ -206,4 +209,79 @@
}
});
});

describe("updateImpersonationRequest", () => {
beforeEach(async () => {
impersonationRequest = await impersonationModel.createImpersonationRequest(impersonationRequestsBodyData[0]);
});

it("should approve an impersonation request", async () => {
const updatedRequest = await impersonationModel.updateImpersonationRequest({

Check failure on line 219 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'updateImpersonationRequest' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
id: impersonationRequest.id,
updatePayload: { status: "APPROVED" },
lastModifiedBy: impersonationRequest.impersonatedUserId,
}) as UpdateImpersonationRequestStatusBody;
expect(updatedRequest.status).to.equal(REQUEST_STATE.APPROVED);
});

it("should reject an impersonation request", async () => {
const updatedRequest = await impersonationModel.updateImpersonationRequest({

Check failure on line 228 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'updateImpersonationRequest' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
id: impersonationRequest.id,
updatePayload: { status: "REJECTED" },
lastModifiedBy: impersonationRequest.impersonatedUserId,
}) as UpdateImpersonationRequestStatusBody;
expect(updatedRequest.status).to.equal(REQUEST_STATE.REJECTED);
});

it("should change the startedAt,endedAt and isImpersonationFinished fields on update", async () => {
const updatedBody = {
isImpersonationFinished: true,
startedAt: Timestamp.fromDate(new Date(Date.now())),
endedAt: Timestamp.fromDate(new Date(Date.now() + 15 * 60 * 1000)),
};
const updatedRequest = await impersonationModel.updateImpersonationRequest({

Check failure on line 242 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'updateImpersonationRequest' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
id: impersonationRequest.id,
updatePayload: updatedBody,
lastModifiedBy: impersonationRequest.userId,
}) as UpdateImpersonationRequestDataResponse;
expect(updatedRequest.isImpersonationFinished).to.be.true;
expect(Number(updatedRequest.startedAt)).to.be.greaterThan(0);
expect(Number(updatedRequest.endedAt)).to.be.greaterThan(Number(updatedRequest.startedAt));
});

it("should change updatedAt timestamp on update", async () => {
const before = Number(impersonationRequest.updatedAt);
const updatedRequest = await impersonationModel.updateImpersonationRequesT({

Check failure on line 254 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'updateImpersonationRequesT' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
id: impersonationRequest.id,
updatePayload: { status: "APPROVED" },
lastModifiedBy: impersonationRequest.impersonatedUserId,
});
const result = await impersonationModel.getImpersonationRequestById(impersonationRequest.id);
expect(result).to.not.be.null;
expect(Number(result.updatedAt)).to.be.greaterThan(before);
});

it("should log and throw error if Firestore update fails in updateImpersonationRequest", async () => {
const error = new Error(ERROR_WHILE_UPDATING_REQUEST);
const loggerStub = sinon.stub(logger, "error");

const docUpdateStub = sinon.stub().rejects(error);
const docStub = sinon.stub().returns({ update: docUpdateStub });
const collectionStub = sinon.stub().returns({ doc: docStub });
sinon.stub(firestore, "collection").callsFake(collectionStub);

try {
await impersonationModel.updateImpersonationRequest({

Check failure on line 274 in test/unit/models/impersonationRequests.test.ts

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'updateImpersonationRequest' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
id: "impersonationRequest.id",
updatePayload: { status: "APPROVED" },
lastModifiedBy: impersonationRequest.impersonatedUserId,
});
expect.fail("Should throw error");
} catch (err) {
expect(loggerStub.called).to.be.true;
expect(loggerStub.firstCall.args[0]).to.include(ERROR_WHILE_UPDATING_REQUEST);
expect(loggerStub.firstCall.args[1]).to.equal(err);
}
});
});
});
Loading
Loading