Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,8 @@ export const INSTITUTION_RESTRICTION_ALREADY_ACTIVE =
*/
export const NO_LOCATION_SELECTED_FOR_DESIGNATION =
"NO_LOCATION_SELECTED_FOR_DESIGNATION";

/**
* Field requirements not valid.
*/
export const FIELD_REQUIREMENTS_NOT_VALID = "FIELD_REQUIREMENTS_NOT_VALID";
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createFakeUser,
createFakeEducationProgram,
saveFakeInstitutionRestriction,
createFakeRestriction,
} from "@sims/test-utils";
import {
AESTGroups,
Expand All @@ -19,6 +20,7 @@ import {
import * as request from "supertest";
import {
EducationProgram,
FieldRequirementType,
Institution,
InstitutionLocation,
NoteType,
Expand All @@ -34,22 +36,47 @@ describe("RestrictionAESTController(e2e)-addInstitutionRestriction.", () => {
let db: E2EDataSources;
let sharedAuditUser: User;
let susRestriction: Restriction;
let remitRestriction: Restriction;
// Institution restriction that is applicable institution level.
let institutionOnlyRestriction: Restriction;

beforeAll(async () => {
const { nestApplication, dataSource } = await createTestingAppModule();
app = nestApplication;
db = createE2EDataSources(dataSource);
sharedAuditUser = await db.user.save(createFakeUser());
// Find the SUS restriction to be used as an example of a valid restriction.
susRestriction = await db.restriction.findOne({
institutionOnlyRestriction = createFakeRestriction({
initialValues: {
restrictionType: RestrictionType.Institution,
metadata: {
fieldRequirements: {
program: FieldRequirementType.NotAllowed,
location: FieldRequirementType.NotAllowed,
},
},
},
});
// SUS and REMIT restrictions.
const susRestrictionPromise = db.restriction.findOne({
select: { id: true },
where: {
restrictionCode: RestrictionCode.SUS,
},
});
const remitRestrictionPromise = db.restriction.findOne({
select: { id: true },
where: {
restrictionCode: RestrictionCode.REMIT,
},
});
[susRestriction, remitRestriction] = await Promise.all([
susRestrictionPromise,
remitRestrictionPromise,
db.restriction.save(institutionOnlyRestriction),
]);
});

it("Should add multiple institution restrictions when a valid payload with multiple locations IDs is submitted.", async () => {
it("Should add multiple SUS institution restrictions when a valid payload with program ID and multiple locations IDs is submitted.", async () => {
// Arrange
const [institution, program, locationIds, [location1, location2]] =
await createInstitutionProgramLocations({ numberLocationsToCreate: 2 });
Expand Down Expand Up @@ -151,6 +178,178 @@ describe("RestrictionAESTController(e2e)-addInstitutionRestriction.", () => {
]);
});

it("Should add multiple REMIT institution restrictions when a valid payload with multiple locations IDs is submitted.", async () => {
// Arrange
const [institution, , locationIds, [location1, location2]] =
await createInstitutionProgramLocations({
skipProgramCreation: true,
numberLocationsToCreate: 2,
});
const ministryUser = await getAESTUser(
db.dataSource,
AESTGroups.BusinessAdministrators,
);
const endpoint = `/aest/restriction/institution/${institution.id}`;
const token = await getAESTToken(AESTGroups.BusinessAdministrators);

// Act/Assert
let createdInstitutionRestrictionIds: number[];
await request(app.getHttpServer())
.post(endpoint)
.send({
restrictionId: remitRestriction.id,
locationIds,
noteDescription: "Add institution restriction note.",
})
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.CREATED)
.expect(({ body }) => {
expect(body).toHaveProperty("ids");
expect(body.ids).toHaveLength(2);
createdInstitutionRestrictionIds = body.ids;
});

// Assert DB changes.
const createdInstitutionRestrictions = await db.institutionRestriction.find(
{
select: {
id: true,
institution: { id: true },
restriction: { id: true },
location: { id: true },
creator: { id: true },
restrictionNote: {
id: true,
noteType: true,
description: true,
creator: { id: true },
},
isActive: true,
},
relations: {
institution: true,
restriction: true,
location: true,
creator: true,
restrictionNote: { creator: true },
},
where: { id: In(createdInstitutionRestrictionIds) },
order: { id: "ASC" },
loadEagerRelations: false,
},
);
// Ensure both restrictions have the same note.
const [createdInstitutionRestriction1, createdInstitutionRestriction2] =
createdInstitutionRestrictions;
expect(createdInstitutionRestriction1.restrictionNote.id).toBe(
createdInstitutionRestriction2.restrictionNote.id,
);
// Validate created institution restrictions.
const ministryUserAudit = { id: ministryUser.id };
expect(createdInstitutionRestrictions).toEqual([
{
id: createdInstitutionRestriction1.id,
institution: { id: institution.id },
restriction: { id: remitRestriction.id },
location: { id: location1.id },
creator: ministryUserAudit,
restrictionNote: {
id: expect.any(Number),
noteType: NoteType.Restriction,
description: "Add institution restriction note.",
creator: ministryUserAudit,
},
isActive: true,
},
{
id: createdInstitutionRestriction2.id,
institution: { id: institution.id },
restriction: { id: remitRestriction.id },
location: { id: location2.id },
creator: ministryUserAudit,
restrictionNote: {
id: expect.any(Number),
noteType: NoteType.Restriction,
description: "Add institution restriction note.",
creator: ministryUserAudit,
},
isActive: true,
},
]);
});

it("Should add a single institution only institution restriction when a valid payload without program ID and location IDs is submitted.", async () => {
// Arrange
const [institution] = await createInstitutionProgramLocations({
skipProgramCreation: true,
numberLocationsToCreate: 0,
});
const ministryUser = await getAESTUser(
db.dataSource,
AESTGroups.BusinessAdministrators,
);
const endpoint = `/aest/restriction/institution/${institution.id}`;
const token = await getAESTToken(AESTGroups.BusinessAdministrators);

// Act/Assert
let createdInstitutionRestrictionId: number;
await request(app.getHttpServer())
.post(endpoint)
.send({
restrictionId: institutionOnlyRestriction.id,
noteDescription: "Add institution restriction note.",
})
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.CREATED)
.expect(({ body }) => {
expect(body).toHaveProperty("ids");
expect(body.ids).toHaveLength(1);
[createdInstitutionRestrictionId] = body.ids;
});

// Assert DB changes.
const createdInstitutionRestriction =
await db.institutionRestriction.findOne({
select: {
id: true,
institution: { id: true },
restriction: { id: true },
creator: { id: true },
restrictionNote: {
id: true,
noteType: true,
description: true,
creator: { id: true },
},
isActive: true,
},
relations: {
institution: true,
restriction: true,
creator: true,
restrictionNote: { creator: true },
},
where: { id: createdInstitutionRestrictionId },
order: { id: "ASC" },
loadEagerRelations: false,
});
// Validate created institution restrictions.
const ministryUserAudit = { id: ministryUser.id };
expect(createdInstitutionRestriction).toEqual({
id: createdInstitutionRestriction.id,
institution: { id: institution.id },
restriction: { id: institutionOnlyRestriction.id },
creator: ministryUserAudit,
restrictionNote: {
id: expect.any(Number),
noteType: NoteType.Restriction,
description: "Add institution restriction note.",
creator: ministryUserAudit,
},
isActive: true,
});
});

it("Should create the institution restriction when there is already an institution restriction, but it is inactive.", async () => {
// Arrange
const [institution, program, locationIds, [location]] =
Expand Down Expand Up @@ -237,7 +436,7 @@ describe("RestrictionAESTController(e2e)-addInstitutionRestriction.", () => {
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.UNPROCESSABLE_ENTITY)
.expect({
message: `Institution restriction ID ${provincialRestriction.id} not found.`,
message: `Restriction ID ${provincialRestriction.id} not found or invalid.`,
error: "Unprocessable Entity",
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
});
Expand Down Expand Up @@ -342,7 +541,7 @@ describe("RestrictionAESTController(e2e)-addInstitutionRestriction.", () => {
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.UNPROCESSABLE_ENTITY)
.expect({
message: "Institution restriction ID 999999 not found.",
message: "Restriction ID 999999 not found or invalid.",
error: "Unprocessable Entity",
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
});
Expand Down Expand Up @@ -371,6 +570,81 @@ describe("RestrictionAESTController(e2e)-addInstitutionRestriction.", () => {
});
});

it("Should throw a bad request exception on add REMIT restriction when no locations were provided in the request payload.", async () => {
// Arrange
const [institution] = await createInstitutionProgramLocations({
skipProgramCreation: true,
numberLocationsToCreate: 0,
});
const endpoint = `/aest/restriction/institution/${institution.id}`;
const token = await getAESTToken(AESTGroups.BusinessAdministrators);
// Act/Assert
await request(app.getHttpServer())
.post(endpoint)
.send({
restrictionId: remitRestriction.id,
noteDescription: "Add institution restriction note.",
})
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.BAD_REQUEST)
.expect({
message: "Field requirement error(s): location is required.",
error: "Bad Request",
statusCode: HttpStatus.BAD_REQUEST,
});
});

it("Should throw a bad request exception on add REMIT restriction when program is provided in the request payload.", async () => {
// Arrange
const [institution, program, locationIds] =
await createInstitutionProgramLocations({
numberLocationsToCreate: 1,
});
const endpoint = `/aest/restriction/institution/${institution.id}`;
const token = await getAESTToken(AESTGroups.BusinessAdministrators);
// Act/Assert
await request(app.getHttpServer())
.post(endpoint)
.send({
restrictionId: remitRestriction.id,
locationIds,
programId: program.id,
noteDescription: "Add institution restriction note.",
})
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.BAD_REQUEST)
.expect({
message: "Field requirement error(s): program is not allowed.",
error: "Bad Request",
statusCode: HttpStatus.BAD_REQUEST,
});
});

it("Should throw a bad request exception on add SUS restriction when no program and locations were provided in the request payload.", async () => {
// Arrange
const [institution] = await createInstitutionProgramLocations({
skipProgramCreation: true,
numberLocationsToCreate: 0,
});
const endpoint = `/aest/restriction/institution/${institution.id}`;
const token = await getAESTToken(AESTGroups.BusinessAdministrators);
// Act/Assert
await request(app.getHttpServer())
.post(endpoint)
.send({
restrictionId: susRestriction.id,
noteDescription: "Add institution restriction note.",
})
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.BAD_REQUEST)
.expect({
message:
"Field requirement error(s): program is required, location is required.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great to see the details in the validations and the validation messages ❤️

error: "Bad Request",
statusCode: HttpStatus.BAD_REQUEST,
});
});

it("Should throw a bad request exception when no locations were provided.", async () => {
// Arrange
const endpoint = "/aest/restriction/institution/999999";
Expand Down
Loading
Loading