Skip to content

Commit cd13f60

Browse files
#5203 - Modified Independent appeal: New "other" appeal to update profile - E2E tests (#5307)
## Unit tests - StudentAppealActionsProcessor-processActions - Should execute actions uniquely when multiple requests with the same actions are part of the same appeal. - Should execute multiple actions and pass the parameters as expected when multiple requests with different actions are part of the same appeal. - Should throw an error when the appeal request has an unknown action. - Should execute the default action when an appeal request has no actions defined. 🤖 - StudentAppealAction-getActionRequests - Should return only the requests that include the matching action type. 🤖 - Should include requests without actions only when the action type is the DEFAULT one (CreateStudentAppealAssessment). 🤖 - StudentAppealAction-hasApprovedAction - Should throw an error when there are no associated requests for the action. 🤖 - Should return true when at least one associated request is approved. 🤖 - Should return false when there are associated requests but none is approved. 🤖 _Note:_ The 🤖 indicates AI-generated-ish tests 😉 ## E2E tests - StudentAppealAESTController(e2e)-approveStudentAppealRequests - Should approve student appeal requests and add note when the appeal with appeal requests submitted for approval are in pending status. 🆙 - Modified independent appeal - Should update the student profile modified independent status as Approved when a valid modified independent appeal is assessed. 🆕 - Should update the student profile modified independent status as Declined when a valid modified independent appeal is assessed. 🆕 - StudentAppealStudentsController(e2e)-submitStudentAppeal 🆕 - Should create a student-only appeal and a Ministry notification for modified independent when the submission is valid. - Should throw an unprocessable entity error for a student-only appeal submission when the same appeal request type is pending review from the Ministry. - Should throw a bad request error for a student-only appeal submission when the form data is invalid. - Should throw a bad request error for a student-only appeal submission when the form path name is invalid. ## Fixes - Adjusted the note type to be saved as "General" for a student-only appeal. - Fixed the wrong appeal request used to update the student profile. It was using the student appeal ID instead of the appeal request ID.
1 parent d14d8c9 commit cd13f60

13 files changed

+855
-25
lines changed

sims.code-workspace

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
"postalcode",
206206
"PPDA",
207207
"PSFS",
208+
"PSTPDT",
208209
"PTSSR",
209210
"PTWTHD",
210211
"roomandboardcostsappeal",

sources/packages/backend/apps/api/src/route-controllers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export * from "./institution/institution.controller.service";
3030
export * from "./student/student.controller.service";
3131
export * from "./student/student.aest.controller";
3232
export * from "./student/student.students.controller";
33+
export * from "./student-appeal/models/student-appeal.dto";
3334
export * from "./student-appeal/student-appeal.students.controller";
3435
export * from "./student-appeal/student-appeal.aest.controller";
3536
export * from "./assessment/assessment.aest.controller";

sources/packages/backend/apps/api/src/route-controllers/student-appeal/_tests_/e2e/student-appeal.aest.controller.approveStudentAppealRequests.e2e-spec.ts

Lines changed: 162 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,34 @@ import {
1313
createFakeStudentAppeal,
1414
createFakeStudentAppealRequest,
1515
saveFakeApplicationDisbursements,
16+
saveFakeStudent,
1617
} from "@sims/test-utils";
17-
import { ApplicationStatus, StudentAppealStatus } from "@sims/sims-db";
18-
import { StudentAppealApprovalAPIInDTO } from "apps/api/src/route-controllers/student-appeal/models/student-appeal.dto";
18+
import {
19+
ApplicationStatus,
20+
AssessmentTriggerType,
21+
ModifiedIndependentStatus,
22+
NoteType,
23+
StudentAppealActionType,
24+
StudentAppealStatus,
25+
} from "@sims/sims-db";
26+
import { StudentAppealApprovalAPIInDTO } from "../../../../route-controllers";
27+
import MockDate from "mockdate";
1928

2029
describe("StudentAppealAESTController(e2e)-approveStudentAppealRequests", () => {
2130
let app: INestApplication;
2231
let db: E2EDataSources;
32+
const MODIFIED_INDEPENDENT_APPEAL = "modifiedindependentappeal";
2333

2434
beforeAll(async () => {
2535
const { nestApplication, dataSource } = await createTestingAppModule();
2636
app = nestApplication;
2737
db = createE2EDataSources(dataSource);
2838
});
2939

40+
beforeEach(async () => {
41+
MockDate.reset();
42+
});
43+
3044
it("Should approve student appeal requests and add note when the appeal with appeal requests submitted for approval are in pending status.", async () => {
3145
// Arrange
3246
// Create a completed application to request change.
@@ -45,60 +59,197 @@ describe("StudentAppealAESTController(e2e)-approveStudentAppealRequests", () =>
4559
appealRequests: [appealRequest],
4660
});
4761
await db.studentAppeal.save(appeal);
48-
const [savedAppealRequest] = appeal.appealRequests;
4962

5063
const endpoint = `/aest/appeal/${appeal.id}/requests`;
5164
const token = await getAESTToken(AESTGroups.BusinessAdministrators);
5265
const payload: StudentAppealApprovalAPIInDTO = {
5366
requests: [
5467
{
55-
id: savedAppealRequest.id,
68+
id: appealRequest.id,
5669
appealStatus: StudentAppealStatus.Approved,
5770
noteDescription: "Approved",
5871
},
5972
],
6073
};
74+
const now = new Date();
75+
MockDate.set(now);
6176

6277
// Act/Assert
6378
await request(app.getHttpServer())
6479
.patch(endpoint)
6580
.send(payload)
6681
.auth(token, BEARER_AUTH_TYPE)
67-
.expect(HttpStatus.OK)
68-
.expect({});
82+
.expect(HttpStatus.OK);
6983
// Check for the appeal and appeal requests in the database.
7084
const updatedAppeal = await db.studentAppeal.findOne({
7185
select: {
7286
id: true,
7387
appealRequests: {
7488
id: true,
7589
appealStatus: true,
90+
assessedDate: true,
7691
assessedBy: { id: true },
77-
note: { description: true },
92+
note: { description: true, noteType: true },
7893
},
94+
studentAssessment: { id: true, triggerType: true },
95+
},
96+
relations: {
97+
appealRequests: { assessedBy: true, note: true },
98+
studentAssessment: true,
7999
},
80-
relations: { appealRequests: { assessedBy: true, note: true } },
81100
where: { id: appeal.id },
82101
});
83102
// Approving ministry user.
84103
const ministryUser = await getAESTUser(
85104
db.dataSource,
86105
AESTGroups.BusinessAdministrators,
87106
);
88-
// Asset updated appeal and appeal request.
107+
// Assert updated appeal and appeal request.
89108
expect(updatedAppeal).toEqual({
90109
id: appeal.id,
110+
studentAssessment: {
111+
id: expect.any(Number),
112+
triggerType: AssessmentTriggerType.StudentAppeal,
113+
},
91114
appealRequests: [
92115
{
93-
id: savedAppealRequest.id,
116+
id: appealRequest.id,
94117
appealStatus: StudentAppealStatus.Approved,
118+
assessedDate: now,
95119
assessedBy: { id: ministryUser.id },
96-
note: { description: "Approved" },
120+
note: { description: "Approved", noteType: NoteType.Application },
97121
},
98122
],
99123
});
100124
});
101125

126+
describe("Modified independent appeal", () => {
127+
for (const modifiedIndependentStatus of [
128+
ModifiedIndependentStatus.Approved,
129+
ModifiedIndependentStatus.Declined,
130+
]) {
131+
it(`Should update the student profile modified independent status as ${modifiedIndependentStatus} when a valid modified independent appeal is assessed.`, async () => {
132+
// Arrange
133+
// Create a completed application to request change.
134+
const student = await saveFakeStudent(db.dataSource);
135+
// Create pending student appeal.
136+
const appealRequest = createFakeStudentAppealRequest(undefined, {
137+
initialValues: {
138+
appealStatus: StudentAppealStatus.Pending,
139+
submittedFormName: MODIFIED_INDEPENDENT_APPEAL,
140+
submittedData: {
141+
actions: [StudentAppealActionType.UpdateModifiedIndependent],
142+
},
143+
},
144+
});
145+
const appeal = createFakeStudentAppeal({
146+
student,
147+
appealRequests: [appealRequest],
148+
});
149+
await db.studentAppeal.save(appeal);
150+
const endpoint = `/aest/appeal/${appeal.id}/requests`;
151+
const token = await getAESTToken(AESTGroups.BusinessAdministrators);
152+
const appealStatus =
153+
modifiedIndependentStatus === ModifiedIndependentStatus.Approved
154+
? StudentAppealStatus.Approved
155+
: StudentAppealStatus.Declined;
156+
const noteDescription = `Assessed as ${modifiedIndependentStatus}`;
157+
const payload: StudentAppealApprovalAPIInDTO = {
158+
requests: [
159+
{
160+
id: appealRequest.id,
161+
appealStatus,
162+
noteDescription,
163+
},
164+
],
165+
};
166+
const now = new Date();
167+
MockDate.set(now);
168+
169+
// Act/Assert
170+
await request(app.getHttpServer())
171+
.patch(endpoint)
172+
.send(payload)
173+
.auth(token, BEARER_AUTH_TYPE)
174+
.expect(HttpStatus.OK);
175+
// Check for the appeal and appeal requests in the database.
176+
const updatedAppeal = await db.studentAppeal.findOne({
177+
select: {
178+
id: true,
179+
student: {
180+
id: true,
181+
modifiedIndependentStatus: true,
182+
modifiedIndependentAppealRequest: { id: true },
183+
modifiedIndependentStatusUpdatedBy: { id: true },
184+
modifiedIndependentStatusUpdatedOn: true,
185+
modifier: { id: true },
186+
updatedAt: true,
187+
},
188+
appealRequests: {
189+
id: true,
190+
appealStatus: true,
191+
assessedBy: { id: true },
192+
assessedDate: true,
193+
modifier: { id: true },
194+
updatedAt: true,
195+
note: { id: true, description: true, noteType: true },
196+
},
197+
application: { id: true },
198+
studentAssessment: { id: true },
199+
},
200+
relations: {
201+
student: {
202+
modifiedIndependentAppealRequest: true,
203+
modifiedIndependentStatusUpdatedBy: true,
204+
modifier: true,
205+
},
206+
appealRequests: { assessedBy: true, note: true, modifier: true },
207+
application: true,
208+
studentAssessment: true,
209+
},
210+
where: { id: appeal.id },
211+
loadEagerRelations: false,
212+
});
213+
// Approving ministry user.
214+
const ministryUser = await getAESTUser(
215+
db.dataSource,
216+
AESTGroups.BusinessAdministrators,
217+
);
218+
// Assert updated appeal, appeal request, and student profile.
219+
const auditUser = { id: ministryUser.id };
220+
expect(updatedAppeal).toEqual({
221+
id: appeal.id,
222+
application: null,
223+
studentAssessment: null,
224+
student: {
225+
id: student.id,
226+
modifiedIndependentStatus,
227+
modifiedIndependentAppealRequest: { id: appealRequest.id },
228+
modifiedIndependentStatusUpdatedBy: auditUser,
229+
modifiedIndependentStatusUpdatedOn: now,
230+
modifier: auditUser,
231+
updatedAt: now,
232+
},
233+
appealRequests: [
234+
{
235+
id: appealRequest.id,
236+
appealStatus,
237+
assessedDate: now,
238+
assessedBy: auditUser,
239+
modifier: auditUser,
240+
updatedAt: now,
241+
note: {
242+
id: expect.any(Number),
243+
description: noteDescription,
244+
noteType: NoteType.General,
245+
},
246+
},
247+
],
248+
});
249+
});
250+
}
251+
});
252+
102253
afterAll(async () => {
103254
await app?.close();
104255
});

0 commit comments

Comments
 (0)