Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
50 changes: 49 additions & 1 deletion test/unit/middlewares/impersonationRequests.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import chai from "chai";
import sinon from "sinon";
import {
createImpersonationRequestValidator
createImpersonationRequestValidator,
updateImpersonationRequestValidator

Check failure on line 5 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,
UpdateImpersonationRequest,

Check failure on line 11 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";

Expand All @@ -23,6 +26,11 @@
reason: "Testing purpose",
};

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

beforeEach(function () {
res = {
boom: {
Expand Down Expand Up @@ -75,4 +83,44 @@
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
);
expect(res.boom.badRequest.calledOnce).to.be.true;
expect(nextSpy.called).to.be.false;
});
});
});
103 changes: 91 additions & 12 deletions test/unit/models/impersonationRequests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
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, REQUEST_ALREADY_PENDING, IMPERSONATION_NOT_COMPLETED } 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 { CreateImpersonationRequestModelDto } from "../../../types/impersonationRequest";

import { UpdateImpersonationRequestStatusBody } from "../../../types/impersonationRequest";
import { Timestamp } from "firebase-admin/firestore";
import firestore from "../../../utils/firestore";
const userData = userDataFixture();
const logger = require("../../../utils/logger");

describe("models/impersonationRequests", () => {
let impersonationRequest;
let mockRequestBody = impersonationRequestsBodyData[0];
let testUserId:string;
const userData = userDataFixture();
let testUserId: string;

beforeEach(async () => {
await cleanDb();
Expand All @@ -25,7 +27,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 @@ -38,7 +40,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 @@ -47,8 +49,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 @@ -68,13 +70,90 @@
}
});

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("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 89 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 98 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 112 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,
});
const result = await impersonationModel.getImpersonationRequestById(impersonationRequest.id);

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

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'getImpersonationRequestById' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
expect(result.isImpersonationFinished).to.be.true;
expect(Number(result.startedAt)).to.be.greaterThan(0);
expect(Number(result.endedAt)).to.be.greaterThan(Number(result.startedAt));
});

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

Check failure on line 125 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);

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

View workflow job for this annotation

GitHub Actions / build (22.10.0)

Property 'getImpersonationRequestById' does not exist on type 'typeof import("/home/runner/work/website-backend/website-backend/models/impersonationRequests")'. Did you mean 'createImpersonationRequest'?
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");

// Stub Firestore collection and doc chain
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 146 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