Skip to content

Commit 647f8f7

Browse files
committed
chore: add more unit tests
1 parent a403d56 commit 647f8f7

6 files changed

Lines changed: 162 additions & 8 deletions

File tree

test/lib/formsClient/getFormTemplate.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
type PrismaClient,
3+
type Template,
34
type TemplateVersion,
45
prisma,
56
} from "@gcforms/database";
@@ -50,6 +51,35 @@ describe("getFormTemplate should", () => {
5051
});
5152
});
5253

54+
// This test can be deleted once form versioning is implemented in Production and migrated old form template database entries to the new versioned schema
55+
it("return a form template even if form versioning is not fully deployed (testing fallback Prisma query)", async () => {
56+
prismaMock.templateVersion.findUnique.mockResolvedValue(null);
57+
58+
prismaMock.template.findUnique.mockResolvedValue({
59+
jsonConfig: {
60+
elements: [
61+
{
62+
id: 1,
63+
type: "textField",
64+
},
65+
],
66+
},
67+
} as unknown as Template);
68+
69+
const formTemplate = await getFormTemplate("clzamy5qv0000115huc4bh90m", 1);
70+
71+
expect(formTemplate).toEqual({
72+
jsonConfig: {
73+
elements: [
74+
{
75+
id: 1,
76+
type: "textField",
77+
},
78+
],
79+
},
80+
});
81+
});
82+
5383
it("throw an error if database has an internal failure", async () => {
5484
const customError = new Error("custom error");
5585
prismaMock.templateVersion.findUnique.mockRejectedValueOnce(customError);

test/lib/vault/mappers/formSubmission.mapper.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ describe("in formSubmission mapper", () => {
2121
});
2222
});
2323

24+
// This test can be deleted once form versioning is well established in Production
25+
it("return proper NewFormSubmission when DynamoDB response does not include a Version attribute (testing backward compatibility with submissions that were produced when form versioning did not exist)", () => {
26+
const newFormSubmission = mapNewFormSubmissionFromDynamoDbResponse({
27+
Name: "18-06-977e7",
28+
CreatedAt: 1750263415913,
29+
});
30+
31+
expect(newFormSubmission).toEqual(
32+
expect.objectContaining({
33+
version: 1,
34+
}),
35+
);
36+
});
37+
2438
it("throw an error when DynamoDB response is incomplete", () => {
2539
expect(() =>
2640
mapNewFormSubmissionFromDynamoDbResponse({
@@ -135,6 +149,23 @@ describe("in formSubmission mapper", () => {
135149
});
136150
});
137151

152+
// This test can be deleted once form versioning is well established in Production
153+
it("return proper FormSubmission when DynamoDB response does not include a Version attribute (testing backward compatibility with submissions that were produced when form versioning did not exist)", () => {
154+
const formSubmission = mapFormSubmissionFromDynamoDbResponse({
155+
CreatedAt: 1750263415913,
156+
"Status#CreatedAt": "New#1750263415913",
157+
ConfirmationCode: "99063d75-9804-4efa-8f4c-605b4ba6ad95",
158+
FormSubmission: '{"1":"Test response"}',
159+
FormSubmissionHash: "5981e9cd2a2f0032e9b8c99eb7bb8841",
160+
});
161+
162+
expect(formSubmission).toEqual(
163+
expect.objectContaining({
164+
version: 1,
165+
}),
166+
);
167+
});
168+
138169
it("throw an error when SubmissionAttachments in DynamoDB response is present but invalid", () => {
139170
expect(() =>
140171
mapFormSubmissionFromDynamoDbResponse({

test/mocks/dynamodb.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export function buildMockedVaultItem(
1010
ConfirmationCode: confirmationCode,
1111
FormSubmission: '{"1":"Test response"}',
1212
FormSubmissionHash: "5981e9cd2a2f0032e9b8c99eb7bb8841",
13+
Version: 8,
1314
};
1415
}

test/operations/retrieveNewSubmissions.v1.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ describe("retrieveNewSubmissionsOperation handler should", () => {
5353
{
5454
name: "ABC",
5555
createdAt: 123,
56+
version: 8,
5657
},
5758
]);
5859

@@ -66,6 +67,7 @@ describe("retrieveNewSubmissionsOperation handler should", () => {
6667
{
6768
createdAt: 123,
6869
name: "ABC",
70+
version: 8,
6971
},
7072
]);
7173
expect(auditLogSpy).toHaveBeenNthCalledWith(1, {

test/operations/retrieveSubmission.v1.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe("retrieveSubmissionOperation handler should", () => {
6060
answers: "",
6161
checksum: "",
6262
attachments: [],
63+
version: 8,
6364
});
6465
getPublicKeyMock.mockResolvedValueOnce("publicKey");
6566
encryptResponseMock.mockReturnValueOnce({
@@ -91,6 +92,7 @@ describe("retrieveSubmissionOperation handler should", () => {
9192
confirmationCode: "",
9293
answers: "",
9394
checksum: "",
95+
version: 8,
9496
}),
9597
);
9698

@@ -117,6 +119,7 @@ describe("retrieveSubmissionOperation handler should", () => {
117119
scanStatus: AttachmentScanStatus.noThreatsFound,
118120
},
119121
],
122+
version: 8,
120123
});
121124
getFormSubmissionAttachmentDownloadLinkMock.mockResolvedValueOnce(
122125
"https://download-link",
@@ -160,6 +163,7 @@ describe("retrieveSubmissionOperation handler should", () => {
160163
isPotentiallyMalicious: false,
161164
},
162165
],
166+
version: 8,
163167
}),
164168
);
165169

@@ -224,6 +228,7 @@ describe("retrieveSubmissionOperation handler should", () => {
224228
scanStatus: attachmentScanStatus,
225229
},
226230
],
231+
version: 8,
227232
});
228233
getFormSubmissionAttachmentDownloadLinkMock.mockResolvedValueOnce(
229234
"https://download-link",
@@ -253,6 +258,7 @@ describe("retrieveSubmissionOperation handler should", () => {
253258
isPotentiallyMalicious,
254259
},
255260
],
261+
version: 8,
256262
}),
257263
);
258264
},
@@ -274,6 +280,7 @@ describe("retrieveSubmissionOperation handler should", () => {
274280
scanStatus: AttachmentScanStatus.noThreatsFound,
275281
},
276282
],
283+
version: 8,
277284
});
278285
getFormSubmissionAttachmentDownloadLinkMock.mockRejectedValueOnce(
279286
new Error("custom error"),
@@ -300,6 +307,7 @@ describe("retrieveSubmissionOperation handler should", () => {
300307
answers: "",
301308
checksum: "",
302309
attachments: [],
310+
version: 8,
303311
});
304312
getPublicKeyMock.mockImplementationOnce(() => {
305313
throw new Error("custom error");

test/operations/retrieveTemplate.v1.test.ts

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,14 @@ vi.mocked(retrieveRequestContextData).mockReturnValue(
1717
);
1818

1919
describe("retrieveTemplateOperation handler should", () => {
20-
const requestMock = getMockReq({
21-
params: {
22-
formId: "clzsn6tao000611j50dexeob0",
23-
},
24-
serviceUserId: "clzsn6tao000611j50dexeob0",
25-
});
26-
2720
const { res: responseMock, next: nextMock, clearMockRes } = getMockRes();
2821

2922
beforeEach(() => {
3023
vi.clearAllMocks();
3124
clearMockRes();
3225
});
3326

34-
it("respond with success when form submission does exist", async () => {
27+
it("respond with success when form template does exist", async () => {
3528
getFormTemplateMock.mockResolvedValueOnce({
3629
jsonConfig: {
3730
elements: [
@@ -43,6 +36,56 @@ describe("retrieveTemplateOperation handler should", () => {
4336
},
4437
});
4538

39+
const requestMock = getMockReq({
40+
params: {
41+
formId: "clzsn6tao000611j50dexeob0",
42+
},
43+
serviceUserId: "clzsn6tao000611j50dexeob0",
44+
});
45+
46+
await retrieveTemplateOperationV1.handler(
47+
requestMock,
48+
responseMock,
49+
nextMock,
50+
);
51+
52+
expect(responseMock.json).toHaveBeenCalledWith({
53+
elements: [
54+
{
55+
id: 1,
56+
type: "textField",
57+
},
58+
],
59+
});
60+
expect(auditLogSpy).toHaveBeenNthCalledWith(1, {
61+
userId: "clzsn6tao000611j50dexeob0",
62+
subject: { type: "Form", id: "clzsn6tao000611j50dexeob0" },
63+
event: "RetrieveTemplate",
64+
});
65+
});
66+
67+
it("respond with success when specific version of a form template does exist", async () => {
68+
getFormTemplateMock.mockResolvedValueOnce({
69+
jsonConfig: {
70+
elements: [
71+
{
72+
id: 1,
73+
type: "textField",
74+
},
75+
],
76+
},
77+
});
78+
79+
const requestMock = getMockReq({
80+
params: {
81+
formId: "clzsn6tao000611j50dexeob0",
82+
},
83+
query: {
84+
version: "8",
85+
},
86+
serviceUserId: "clzsn6tao000611j50dexeob0",
87+
});
88+
4689
await retrieveTemplateOperationV1.handler(
4790
requestMock,
4891
responseMock,
@@ -67,6 +110,13 @@ describe("retrieveTemplateOperation handler should", () => {
67110
it("respond with error when form template does not exist", async () => {
68111
getFormTemplateMock.mockResolvedValueOnce(undefined);
69112

113+
const requestMock = getMockReq({
114+
params: {
115+
formId: "clzsn6tao000611j50dexeob0",
116+
},
117+
serviceUserId: "clzsn6tao000611j50dexeob0",
118+
});
119+
70120
await retrieveTemplateOperationV1.handler(
71121
requestMock,
72122
responseMock,
@@ -79,9 +129,41 @@ describe("retrieveTemplateOperation handler should", () => {
79129
});
80130
});
81131

132+
it("respond with error when 'version' query parameter is not a number", async () => {
133+
getFormTemplateMock.mockRejectedValueOnce(new Error("custom error"));
134+
135+
const requestMock = getMockReq({
136+
params: {
137+
formId: "clzsn6tao000611j50dexeob0",
138+
},
139+
query: {
140+
version: "hello",
141+
},
142+
serviceUserId: "clzsn6tao000611j50dexeob0",
143+
});
144+
145+
await retrieveTemplateOperationV1.handler(
146+
requestMock,
147+
responseMock,
148+
nextMock,
149+
);
150+
151+
expect(responseMock.status).toHaveBeenCalledWith(400);
152+
expect(responseMock.json).toHaveBeenCalledWith({
153+
error: "URL parameter 'version' should be a number",
154+
});
155+
});
156+
82157
it("pass error to next function when processing fails due to internal error", async () => {
83158
getFormTemplateMock.mockRejectedValueOnce(new Error("custom error"));
84159

160+
const requestMock = getMockReq({
161+
params: {
162+
formId: "clzsn6tao000611j50dexeob0",
163+
},
164+
serviceUserId: "clzsn6tao000611j50dexeob0",
165+
});
166+
85167
await retrieveTemplateOperationV1.handler(
86168
requestMock,
87169
responseMock,

0 commit comments

Comments
 (0)