Skip to content

Commit 4ed9bf9

Browse files
committed
chore: update getDataOutMetadata and tests
1 parent cf8f9b5 commit 4ed9bf9

File tree

2 files changed

+81
-36
lines changed

2 files changed

+81
-36
lines changed

packages/backend/src/apps/formsg/__tests__/triggers/new-submission.test.ts

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88

99
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
1010

11+
import apps from '@/apps'
12+
1113
import { ADDRESS_LABELS } from '../../common/constants'
1214
import trigger from '../../triggers/new-submission'
1315

@@ -24,6 +26,7 @@ const mocks = vi.hoisted(() => ({
2426
},
2527
}
2628
}),
29+
removeMrfSteps: vi.fn(),
2730
}))
2831

2932
vi.mock('../../triggers/new-submission/get-mock-data', () => ({
@@ -34,12 +37,26 @@ vi.mock('../../triggers/new-submission/fetch-form-schema', () => ({
3437
fetchFormSchema: mocks.fetchFormSchema,
3538
}))
3639

40+
vi.mock('../../triggers/new-submission/remove-mrf-steps', () => ({
41+
removeMrfSteps: mocks.removeMrfSteps,
42+
}))
43+
3744
vi.mock('../../common/webhook-settings', () => ({
3845
registerWebhookUrl: vi.fn(),
3946
verifyWebhookUrl: vi.fn(),
4047
getFormDetailsFromGlobalVariable: mocks.getFormDetailsFromGlobalVariable,
4148
}))
4249

50+
vi.mock('../../../../models/step', () => ({
51+
default: {
52+
query: vi.fn(() => ({
53+
findById: vi.fn(() => ({
54+
throwIfNotFound: vi.fn(() => ({ parameters: {} })),
55+
})),
56+
})),
57+
},
58+
}))
59+
4360
describe('new submission trigger', () => {
4461
let executionStep: IExecutionStep
4562

@@ -72,12 +89,24 @@ describe('new submission trigger', () => {
7289
} as unknown as IExecutionStep
7390
})
7491

92+
afterEach(() => {
93+
vi.clearAllMocks()
94+
})
95+
7596
describe('testRun', () => {
7697
const $ = {
7798
auth: { data: { formId: '123' } },
7899
user: { email: '[email protected]' },
100+
step: {
101+
id: '123',
102+
position: 1,
103+
},
104+
flow: {
105+
id: 'flow-id',
106+
},
79107
pushTriggerItem: pushTriggerItemMock,
80108
getLastExecutionStep: getLastExecutionStepMock,
109+
app: apps.formsg,
81110
} as unknown as IGlobalVariable
82111

83112
const mockData = {
@@ -108,10 +137,6 @@ describe('new submission trigger', () => {
108137
})
109138
})
110139

111-
afterEach(() => {
112-
vi.clearAllMocks()
113-
})
114-
115140
it('should use mock data if preferMock is true and there is no past submission', async () => {
116141
getLastExecutionStepMock.mockResolvedValue(null)
117142
await trigger.testRun($, { preferMock: true })
@@ -223,6 +248,12 @@ describe('new submission trigger', () => {
223248
},
224249
})
225250
})
251+
252+
it('should call remove MRF steps function if the form is storage mode', async () => {
253+
getLastExecutionStepMock.mockResolvedValue(null)
254+
await trigger.testRun($, { preferMock: false })
255+
expect(mocks.removeMrfSteps).toHaveBeenCalledOnce()
256+
})
226257
})
227258
describe('dataOut metadata', () => {
228259
it('ensures that only question, answer and answerArray props are visible', async () => {
@@ -355,7 +386,7 @@ describe('new submission trigger', () => {
355386
)
356387
})
357388

358-
it('sets label to the associated question for attachment answers', async () => {
389+
it('sets label to the associated question for attachment answers with question number', async () => {
359390
executionStep.dataOut.fields = {
360391
fileFieldId: {
361392
question: 'Attach a file.',
@@ -365,14 +396,14 @@ describe('new submission trigger', () => {
365396
}
366397

367398
const metadata = await trigger.getDataOutMetadata(executionStep)
368-
expect(metadata.fields.fileFieldId.answer.label).toEqual('Attach a file.')
399+
expect(metadata.fields.fileFieldId.answer.label).toEqual(
400+
'1. Attach a file.',
401+
)
369402
})
370403

371-
it('collapses header fields', async () => {
404+
it('hides header fields', async () => {
372405
const metadata = await trigger.getDataOutMetadata(executionStep)
373-
expect(
374-
metadata.fields.headerFieldId.question.isCollapsedByDefault,
375-
).toEqual(true)
406+
expect(metadata.fields.headerFieldId.isHidden).toEqual(true)
376407
})
377408

378409
it('collapses question variables', async () => {

packages/backend/src/apps/formsg/common/get-data-out-metadata.ts

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import {
99

1010
import logger from '@/helpers/logger'
1111
import { parseS3Id } from '@/helpers/s3'
12+
import Step from '@/models/step'
1213

1314
import { ADDRESS_LABELS } from './constants'
15+
import { ParsedMrfWorkflowStep } from './types'
1416

1517
function buildQuestionMetadatum(fieldData: IJSONObject): IDataOutMetadatum {
1618
const question: IDataOutMetadatum = {
@@ -44,7 +46,7 @@ function buildAnswerMetadatum(fieldData: IJSONObject): IDataOutMetadatum {
4446
answer['type'] = 'file'
4547
// We encode the question as the label because we hide the actual question
4648
// as a variable.
47-
answer['label'] = fieldData.question as string
49+
answer['label'] = `${fieldData.order}. ${fieldData.question}` as string
4850
// For attachments, answer is one of:
4951
// 1. An S3 ID (if we stored the attachment into S3).
5052
// 2. An empty string (if attachment field is optional).
@@ -327,6 +329,18 @@ async function getDataOutMetadata(
327329
return null
328330
}
329331

332+
const { parameters } = await Step.query()
333+
.findById(executionStep.stepId)
334+
.throwIfNotFound()
335+
336+
let questionIdsToShowForMrf: Set<string> | undefined
337+
338+
if (parameters.mrf) {
339+
questionIdsToShowForMrf = new Set(
340+
(parameters.mrf as ParsedMrfWorkflowStep).fields,
341+
)
342+
}
343+
330344
const fieldMetadata: IDataOutMetadata = Object.create(null)
331345

332346
const fields = Object.entries(data.fields).sort((a, b) => {
@@ -339,35 +353,35 @@ async function getDataOutMetadata(
339353
})
340354

341355
/**
342-
* This is a hack to match the question number to the form as closely as possible.
343-
* In formsg, the headers are not numbered, so we need to exclude them from the question number.
344-
* But we also need to keep track of the headers between questions, so we can order them correctly.
345-
* The regenerated order will be like so:
346-
* Example given form:
347-
* Header 0.9991
348-
* Header 0.9992
349-
* Question 1
350-
* Question 2
351-
* Sub Heading 2.9991
352-
* Question 3
353-
* Header 3.9991
354-
* Sub Heading 3.9992
355-
* Question 4
356-
* Sub Heading 4.9991
357-
* Question 4
356+
* We ignore all 'image' and 'section' (aka headers) field types
357+
* Paragraphs are not returned in encryptedContent
358358
*/
359359
let questionOrder = 0
360-
let headerOrderBetweenQuestions = 0
361360
for (const [fieldId, fieldData] of fields) {
362-
if (fieldData.fieldType !== 'section') {
363-
// reset order between questions (altho not necessary)
364-
headerOrderBetweenQuestions = 0
365-
questionOrder++
366-
fieldData.order = questionOrder
367-
} else {
368-
headerOrderBetweenQuestions++
369-
fieldData.order = questionOrder + +`0.999${headerOrderBetweenQuestions}`
361+
// ignore image fields, dont even increment question order
362+
if (fieldData.fieldType === 'image' || fieldData.fieldType === 'section') {
363+
fieldMetadata[fieldId] = { isHidden: true }
364+
continue
370365
}
366+
367+
// increment question order for each field
368+
questionOrder++
369+
fieldData.order = questionOrder
370+
371+
// if this is an MRF step, we only show the fields that are editable
372+
if (questionIdsToShowForMrf && !questionIdsToShowForMrf.has(fieldId)) {
373+
fieldMetadata[fieldId] = {
374+
question: { isHidden: true },
375+
answer: { isHidden: true },
376+
fieldType: { isHidden: true },
377+
order: { isHidden: true },
378+
myInfo: { attr: { isHidden: true } },
379+
isVisible: { isHidden: true },
380+
isHeader: { isHidden: true },
381+
}
382+
continue
383+
}
384+
371385
fieldMetadata[fieldId] = {
372386
question: buildQuestionMetadatum(fieldData),
373387
answer: buildAnswerMetadatum(fieldData),

0 commit comments

Comments
 (0)