Skip to content

Commit 4c8f492

Browse files
authored
[REMOCK-3] PLU-471: store last test submission date for frontend rendering (#1062)
## Summary Add lastTestSubmissionTime to formsg execution step metadata. This is to allow the frontend to know if an actual submission exists. 1. Move `isMock` into the metadata object instead of being a separate property 3. Adding `lastTestSubmissionDate` to metadata to track when the last test submission occurred 4. Using the submission time when available, falling back to createdAt when not available These changes will help the frontend determine if there's a past test submission and display appropriate information to users.
1 parent b45cde9 commit 4c8f492

File tree

6 files changed

+72
-12
lines changed

6 files changed

+72
-12
lines changed

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

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ describe('new submission trigger', () => {
7979

8080
const actualData = {
8181
formId: '123',
82+
submissionTime: '2025-06-17T14:25:14.195+08:00',
8283
responses: {
8384
textFieldId: {
8485
question: 'What is your age?',
@@ -105,20 +106,27 @@ describe('new submission trigger', () => {
105106
raw: mockData,
106107
meta: {
107108
internalId: '',
109+
isMock: true,
110+
lastTestSubmissionDate: undefined,
108111
},
109-
isMock: true,
110112
})
111113
})
112114

113115
it('should use mock data if preferMock is true even though there is past submission', async () => {
114-
getLastExecutionStepMock.mockResolvedValue({ dataOut: actualData })
116+
getLastExecutionStepMock.mockResolvedValue({
117+
dataOut: actualData,
118+
createdAt: '2025-06-16 07:06:30.155+00',
119+
})
115120
await trigger.testRun($, { preferMock: true })
116121
expect(pushTriggerItemMock).toHaveBeenCalledWith({
117122
raw: mockData,
118123
meta: {
119124
internalId: '',
125+
isMock: true,
126+
lastTestSubmissionDate: new Date(
127+
'2025-06-17T14:25:14.195+08:00',
128+
).toISOString(),
120129
},
121-
isMock: true,
122130
})
123131
})
124132

@@ -129,32 +137,45 @@ describe('new submission trigger', () => {
129137
raw: mockData,
130138
meta: {
131139
internalId: '',
140+
isMock: true,
141+
lastTestSubmissionDate: undefined,
132142
},
133-
isMock: true,
134143
})
135144
})
136145

137146
it('should use last test submission if testRunMetadata is undefined and there is past submission', async () => {
138-
getLastExecutionStepMock.mockResolvedValue({ dataOut: actualData })
147+
getLastExecutionStepMock.mockResolvedValue({
148+
dataOut: actualData,
149+
createdAt: '2025-06-16 07:06:30.155+00',
150+
})
139151
await trigger.testRun($, undefined)
140152
expect(pushTriggerItemMock).toHaveBeenCalledWith({
141153
raw: actualData,
142154
meta: {
143155
internalId: '',
156+
isMock: false,
157+
lastTestSubmissionDate: new Date(
158+
'2025-06-17T14:25:14.195+08:00',
159+
).toISOString(),
144160
},
145-
isMock: false,
146161
})
147162
})
148163

149164
it('should use last test submission if preferMock is false and there is past submission', async () => {
150-
getLastExecutionStepMock.mockResolvedValue({ dataOut: actualData })
165+
getLastExecutionStepMock.mockResolvedValue({
166+
dataOut: actualData,
167+
createdAt: '2025-06-16 07:06:30.155+00',
168+
})
151169
await trigger.testRun($, { preferMock: false })
152170
expect(pushTriggerItemMock).toHaveBeenCalledWith({
153171
raw: actualData,
154172
meta: {
155173
internalId: '',
174+
isMock: false,
175+
lastTestSubmissionDate: new Date(
176+
'2025-06-17T14:25:14.195+08:00',
177+
).toISOString(),
156178
},
157-
isMock: false,
158179
})
159180
})
160181

@@ -165,8 +186,28 @@ describe('new submission trigger', () => {
165186
raw: mockData,
166187
meta: {
167188
internalId: '',
189+
isMock: true,
190+
lastTestSubmissionDate: undefined,
191+
},
192+
})
193+
})
194+
195+
it('should store the createdAt time if submissionTime is not available', async () => {
196+
getLastExecutionStepMock.mockResolvedValue({
197+
dataOut: { ...actualData, submissionTime: undefined },
198+
createdAt: '2025-06-16 07:06:30.155+00',
199+
})
200+
await trigger.testRun($, { preferMock: false })
201+
202+
expect(pushTriggerItemMock).toHaveBeenCalledWith({
203+
raw: { ...actualData, submissionTime: undefined },
204+
meta: {
205+
internalId: '',
206+
isMock: false,
207+
lastTestSubmissionDate: new Date(
208+
'2025-06-16 07:06:30.155+00',
209+
).toISOString(),
168210
},
169-
isMock: true,
170211
})
171212
})
172213
})

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,23 @@ const trigger: IRawTrigger = {
112112
? await getMockData($)
113113
: lastSubmittedTestExecutionStep?.dataOut
114114

115+
// If for some reason the submission time is not available, use the createdAt time
116+
const lastFormSubmissionTime =
117+
(lastSubmittedTestExecutionStep?.dataOut?.submissionTime as string) ??
118+
lastSubmittedTestExecutionStep?.createdAt
119+
120+
const lastTestSubmissionDate = lastFormSubmissionTime
121+
? new Date(lastFormSubmissionTime).toISOString()
122+
: undefined
123+
115124
// if different or no form is detected, use mock data
116125
await $.pushTriggerItem({
117126
raw: testData,
118127
meta: {
119128
internalId: '',
129+
isMock: shouldUseMockData,
130+
lastTestSubmissionDate,
120131
},
121-
isMock: shouldUseMockData,
122132
})
123133
},
124134
}

packages/backend/src/graphql/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ type ExecutionStep {
320320

321321
type ExecutionStepMetadata {
322322
isMock: Boolean
323+
lastTestSubmissionDate: String
323324
}
324325

325326
type Field {

packages/backend/src/models/execution-step.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class ExecutionStep extends Base {
4141
isMock: {
4242
type: 'boolean',
4343
},
44+
// this is purely used to tell frontend that there is a past test submission
45+
lastTestSubmissionDate: {
46+
type: 'string',
47+
},
4448
},
4549
},
4650
},

packages/backend/src/services/trigger.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ export const processTrigger = async (options: ProcessTriggerOptions) => {
7979
...(error && { status: 'failure' }),
8080
})
8181

82+
// We store all metadata except internalId
83+
const { internalId: _, ...metadataToStore } = triggerItem?.meta ?? {}
84+
8285
const executionStep = await execution
8386
.$relatedQuery('executionSteps')
8487
.insertAndFetch({
@@ -88,7 +91,7 @@ export const processTrigger = async (options: ProcessTriggerOptions) => {
8891
dataOut: !error ? triggerItem?.raw : null,
8992
errorDetails: error,
9093
appKey: step.appKey,
91-
metadata: triggerItem?.isMock ? { isMock: true } : {},
94+
metadata: metadataToStore ?? {},
9295
})
9396

9497
return {

packages/types/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export interface IExecutionStep {
127127

128128
export interface IExecutionStepMetadata {
129129
isMock?: boolean
130+
lastTestSubmissionDate?: string
130131
}
131132

132133
export interface IExecution {
@@ -633,8 +634,8 @@ export interface ITriggerItem {
633634
raw: IJSONObject
634635
meta: {
635636
internalId: string
637+
[key: string]: unknown
636638
}
637-
isMock?: boolean
638639
}
639640

640641
export type ITriggerInstructions = Partial<{

0 commit comments

Comments
 (0)