Skip to content

Commit d3b6611

Browse files
authored
PLU-393: Variables: keys with . may be single key or nested path (#831)
### TL;DR New MyInfo Child fields from FormSG returns data with `.` as part of the key (e.g., `child.birthdate`). Libraries like `lodash.get` treat `.` as a path separator for nested properties (e.g., accessing `child.birthdate`), leading to incorrect value retrieval or failure. ### What changed? - Replaced the `.` in keys with `_` to avoid issues with obtaining values. ### How to test? 1. Run the test suite to verify all scenarios pass 2. Test with actual FormSG fields from MyInfo Child ### Why make this change? The standard lodash.get function doesn't properly handle cases where object keys contain dots, leading to incorrect property access. This implementation provides more accurate property resolution.
1 parent 35f179f commit d3b6611

File tree

3 files changed

+125
-1
lines changed

3 files changed

+125
-1
lines changed

packages/backend/src/apps/formsg/__tests__/auth/decrypt-form-response.test.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,98 @@ describe('decrypt form response', () => {
410410
}),
411411
)
412412
})
413+
414+
it('should parse form fields and replace dots with underscores in keys', async () => {
415+
mockDecryptedSubmission({
416+
responses: [
417+
{
418+
_id: 'question1.field.answer',
419+
fieldType: 'textarea',
420+
question: 'What do you eat for breakfast?',
421+
answer: 'i eat lorem dimsum for breakfast',
422+
},
423+
{
424+
_id: 'question2.field.answer',
425+
fieldType: 'mobile',
426+
question: 'What is your mobile number?',
427+
answer: '+6591234567',
428+
},
429+
],
430+
})
431+
await expect(decryptFormResponse($)).resolves.toEqual(true)
432+
expect($.request.body).toEqual(
433+
expect.objectContaining({
434+
fields: {
435+
question1_field_answer: {
436+
fieldType: 'textarea',
437+
question: 'What do you eat for breakfast?',
438+
answer: 'i eat lorem dimsum for breakfast',
439+
order: 1,
440+
},
441+
question2_field_answer: {
442+
fieldType: 'mobile',
443+
question: 'What is your mobile number?',
444+
answer: '+6591234567',
445+
order: 2,
446+
},
447+
},
448+
}),
449+
)
450+
expect($.request.headers).toBeUndefined()
451+
expect($.request.query).toBeUndefined()
452+
})
453+
454+
it('should parse form fields and replace dots with underscores in keys', async () => {
455+
mockDecryptedSubmission({
456+
responses: [
457+
{
458+
_id: 'childrenbirthrecords.abc.childdateofbirth.0',
459+
fieldType: 'children',
460+
question: 'Child Date of birth',
461+
answer: '31/03/2017',
462+
},
463+
{
464+
_id: 'childrenbirthrecords.abc.childname.0',
465+
fieldType: 'children',
466+
question: 'Child Name',
467+
answer: 'John Doe',
468+
},
469+
{
470+
_id: 'question2.field.answer',
471+
fieldType: 'mobile',
472+
question: 'What is your mobile number?',
473+
answer: '+6591234567',
474+
},
475+
],
476+
})
477+
await expect(decryptFormResponse($)).resolves.toEqual(true)
478+
expect($.request.body).toEqual(
479+
expect.objectContaining({
480+
fields: {
481+
childrenbirthrecords_abc_childdateofbirth_0: {
482+
fieldType: 'children',
483+
question: 'Child Date of birth',
484+
answer: '31/03/2017',
485+
order: 1,
486+
},
487+
childrenbirthrecords_abc_childname_0: {
488+
fieldType: 'children',
489+
question: 'Child Name',
490+
answer: 'John Doe',
491+
order: 2,
492+
},
493+
question2_field_answer: {
494+
fieldType: 'mobile',
495+
question: 'What is your mobile number?',
496+
answer: '+6591234567',
497+
order: 3,
498+
},
499+
},
500+
}),
501+
)
502+
expect($.request.headers).toBeUndefined()
503+
expect($.request.query).toBeUndefined()
504+
})
413505
})
414506

415507
describe('attachments', () => {

packages/backend/src/apps/formsg/auth/decrypt-form-response.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ export async function decryptFormResponse(
121121

122122
// Note: the order may not be sequential; fields (e.g. NRIC) can be
123123
// omitted from the output.
124-
parsedData[_id] = {
124+
// Note: FormSG uses dot notation for field ids for MyInfo children
125+
// we replace with underscore to avoid issues when using lodash get.
126+
parsedData[_id.replaceAll('.', '_')] = {
125127
order: index + 1,
126128
...rest,
127129
}

packages/backend/src/helpers/__tests__/compute-parameters.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,4 +319,34 @@ describe('compute parameters', () => {
319319
const result = computeParameters(params, executionStep)
320320
expect(result).toEqual(expected)
321321
})
322+
323+
it('should process parameters with underscores in keys', () => {
324+
const executionStep = [
325+
{
326+
stepId: randomStepID,
327+
dataOut: {
328+
childrenbirthrecords_abc_childdateofbirth_0: {
329+
fieldType: 'children',
330+
question: 'Child Date of birth',
331+
answer: '31/03/2017',
332+
order: 1,
333+
},
334+
childrenbirthrecords_abc_childname_0: {
335+
fieldType: 'children',
336+
question: 'Child Name',
337+
answer: 'John Doe',
338+
order: 2,
339+
},
340+
},
341+
} as unknown as ExecutionStep,
342+
]
343+
const params = {
344+
toSubstitute: `{{step.${randomStepID}.childrenbirthrecords_abc_childdateofbirth_0.answer}} {{step.${randomStepID}.childrenbirthrecords_abc_childname_0.answer}}`,
345+
}
346+
const expected = {
347+
toSubstitute: `31/03/2017 John Doe`,
348+
}
349+
const result = computeParameters(params, executionStep)
350+
expect(result).toEqual(expected)
351+
})
322352
})

0 commit comments

Comments
 (0)