@defra/forms-engine-plugin 2.1.4 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +2 -2
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.d.ts +2 -2
- package/.server/server/plugins/engine/components/ComponentCollection.js +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/TelephoneNumberField.js +1 -1
- package/.server/server/plugins/engine/components/TelephoneNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.js +1 -1
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/{helpers.d.ts → helpers/components.d.ts} +3 -10
- package/.server/server/plugins/engine/components/{helpers.js → helpers/components.js} +16 -29
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/index.d.ts +11 -0
- package/.server/server/plugins/engine/components/helpers/index.js +15 -0
- package/.server/server/plugins/engine/components/helpers/index.js.map +1 -0
- package/.server/server/plugins/engine/helpers.d.ts +1 -1
- package/.server/server/plugins/engine/helpers.js +1 -1
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +2 -2
- package/.server/server/plugins/engine/models/FormModel.js +2 -2
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js +1 -1
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/models/types.d.ts +2 -2
- package/.server/server/plugins/engine/models/types.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +6 -0
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +23 -0
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -0
- package/.server/server/plugins/engine/outputFormatters/human/v1.d.ts +2 -2
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +3 -2
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/index.d.ts +4 -3
- package/.server/server/plugins/engine/outputFormatters/index.js +4 -0
- package/.server/server/plugins/engine/outputFormatters/index.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v1.d.ts +2 -2
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js +2 -2
- package/.server/server/plugins/engine/outputFormatters/machine/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +4 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +6 -5
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/index.d.ts +9 -0
- package/.server/server/plugins/engine/pageControllers/helpers/index.js +15 -0
- package/.server/server/plugins/engine/pageControllers/helpers/index.js.map +1 -0
- package/.server/server/plugins/engine/pageControllers/{helpers.d.ts → helpers/pages.d.ts} +1 -10
- package/.server/server/plugins/engine/pageControllers/{helpers.js → helpers/pages.js} +2 -17
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -0
- package/.server/server/plugins/engine/routes/index.d.ts +1 -1
- package/.server/server/plugins/engine/routes/index.js.map +1 -1
- package/.server/server/plugins/engine/routes/questions.js.map +1 -1
- package/.server/server/plugins/engine/services/localFormsService.d.ts +1 -1
- package/.server/server/plugins/engine/services/notifyService.d.ts +7 -2
- package/.server/server/plugins/engine/services/notifyService.js +12 -3
- package/.server/server/plugins/engine/services/notifyService.js.map +1 -1
- package/.server/server/plugins/engine/types/index.d.ts +10 -0
- package/.server/server/plugins/engine/types/index.js +4 -0
- package/.server/server/plugins/engine/types/index.js.map +1 -0
- package/.server/server/plugins/engine/types/schema.d.ts +5 -0
- package/.server/server/plugins/engine/types/schema.js +24 -0
- package/.server/server/plugins/engine/types/schema.js.map +1 -0
- package/.server/server/plugins/engine/types.d.ts +39 -3
- package/.server/server/plugins/engine/types.js +4 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/answer.js +2 -2
- package/.server/server/plugins/nunjucks/filters/answer.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/answer.test.js +2 -2
- package/.server/server/plugins/nunjucks/filters/answer.test.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/nunjucks/filters/page.d.ts +1 -1
- package/.server/server/types.d.ts +1 -1
- package/.server/server/types.js.map +1 -1
- package/package.json +6 -1
- package/src/server/plugins/engine/components/AutocompleteField.test.ts +1 -1
- package/src/server/plugins/engine/components/CheckboxesField.test.ts +1 -1
- package/src/server/plugins/engine/components/ComponentBase.ts +2 -2
- package/src/server/plugins/engine/components/ComponentCollection.ts +2 -2
- package/src/server/plugins/engine/components/DatePartsField.test.ts +1 -1
- package/src/server/plugins/engine/components/Details.test.ts +1 -1
- package/src/server/plugins/engine/components/EmailAddressField.test.ts +1 -1
- package/src/server/plugins/engine/components/FileUploadField.test.ts +2 -2
- package/src/server/plugins/engine/components/Html.test.ts +1 -1
- package/src/server/plugins/engine/components/InsetText.test.ts +1 -1
- package/src/server/plugins/engine/components/List.test.ts +1 -1
- package/src/server/plugins/engine/components/Markdown.test.ts +1 -1
- package/src/server/plugins/engine/components/MonthYearField.test.ts +1 -1
- package/src/server/plugins/engine/components/MultilineTextField.test.ts +1 -1
- package/src/server/plugins/engine/components/NumberField.test.ts +1 -1
- package/src/server/plugins/engine/components/RadiosField.test.ts +1 -1
- package/src/server/plugins/engine/components/SelectField.test.ts +1 -1
- package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +1 -1
- package/src/server/plugins/engine/components/TelephoneNumberField.ts +1 -1
- package/src/server/plugins/engine/components/TextField.test.ts +1 -1
- package/src/server/plugins/engine/components/UkAddressField.test.ts +1 -1
- package/src/server/plugins/engine/components/YesNoField.test.ts +1 -1
- package/src/server/plugins/engine/components/YesNoField.ts +1 -1
- package/src/server/plugins/engine/components/{helpers.ts → helpers/components.ts} +41 -77
- package/src/server/plugins/engine/components/{helpers.test.ts → helpers/helpers.test.ts} +1 -1
- package/src/server/plugins/engine/components/helpers/index.ts +38 -0
- package/src/server/plugins/engine/helpers.test.ts +1 -1
- package/src/server/plugins/engine/helpers.ts +2 -2
- package/src/server/plugins/engine/models/FormModel.ts +2 -2
- package/src/server/plugins/engine/models/SummaryViewModel.test.ts +1 -1
- package/src/server/plugins/engine/models/SummaryViewModel.ts +2 -2
- package/src/server/plugins/engine/models/types.ts +4 -4
- package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +506 -0
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +53 -0
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +8 -6
- package/src/server/plugins/engine/outputFormatters/index.ts +11 -3
- package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +1 -1
- package/src/server/plugins/engine/outputFormatters/machine/v1.ts +7 -3
- package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +1 -1
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +1 -1
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +1 -1
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +1 -1
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +16 -5
- package/src/server/plugins/engine/pageControllers/{helpers.test.ts → helpers/helpers.test.ts} +2 -2
- package/src/server/plugins/engine/pageControllers/helpers/index.ts +20 -0
- package/src/server/plugins/engine/pageControllers/{helpers.ts → helpers/pages.ts} +1 -22
- package/src/server/plugins/engine/routes/index.ts +1 -1
- package/src/server/plugins/engine/routes/questions.test.ts +1 -1
- package/src/server/plugins/engine/routes/questions.ts +1 -1
- package/src/server/plugins/engine/services/notifyService.test.ts +156 -1
- package/src/server/plugins/engine/services/notifyService.ts +25 -4
- package/src/server/plugins/engine/types/index.ts +96 -0
- package/src/server/plugins/engine/types/schema.test.ts +152 -0
- package/src/server/plugins/engine/types/schema.ts +45 -0
- package/src/server/plugins/engine/types.ts +53 -3
- package/src/server/plugins/nunjucks/filters/answer.js +2 -2
- package/src/server/plugins/nunjucks/filters/answer.test.js +7 -4
- package/src/server/types.ts +2 -1
- package/.server/server/plugins/engine/components/helpers.js.map +0 -1
- package/.server/server/plugins/engine/pageControllers/helpers.js.map +0 -1
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { type FormMetadata } from '@defra/forms-model'
|
|
2
|
+
|
|
3
|
+
import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
|
|
4
|
+
import { type Field } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
5
|
+
import { FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
6
|
+
import {
|
|
7
|
+
type DetailItem,
|
|
8
|
+
type DetailItemField,
|
|
9
|
+
type DetailItemRepeat
|
|
10
|
+
} from '~/src/server/plugins/engine/models/types.js'
|
|
11
|
+
import { format } from '~/src/server/plugins/engine/outputFormatters/adapter/v1.js'
|
|
12
|
+
import { buildFormContextRequest } from '~/src/server/plugins/engine/pageControllers/__stubs__/request.js'
|
|
13
|
+
import {
|
|
14
|
+
FileStatus,
|
|
15
|
+
FormAdapterSubmissionSchemaVersion,
|
|
16
|
+
UploadStatus,
|
|
17
|
+
type FileState,
|
|
18
|
+
type FormAdapterSubmissionMessagePayload
|
|
19
|
+
} from '~/src/server/plugins/engine/types.js'
|
|
20
|
+
import { FormStatus } from '~/src/server/routes/types.js'
|
|
21
|
+
import definition from '~/test/form/definitions/repeat-mixed.js'
|
|
22
|
+
|
|
23
|
+
const submitResponse = {
|
|
24
|
+
message: 'Submit completed',
|
|
25
|
+
result: {
|
|
26
|
+
files: {
|
|
27
|
+
main: '00000000-0000-0000-0000-000000000000',
|
|
28
|
+
repeaters: {
|
|
29
|
+
pizza: '11111111-1111-1111-1111-111111111111'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const model = new FormModel(definition, {
|
|
36
|
+
basePath: 'test'
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const dummyField: Field = {
|
|
40
|
+
getFormValueFromState: (_) => 'hello world'
|
|
41
|
+
} as Field
|
|
42
|
+
|
|
43
|
+
const itemId1 = 'abc-123'
|
|
44
|
+
const itemId2 = 'xyz-987'
|
|
45
|
+
|
|
46
|
+
const state = {
|
|
47
|
+
$$__referenceNumber: 'foobar',
|
|
48
|
+
orderType: 'delivery',
|
|
49
|
+
pizza: [
|
|
50
|
+
{
|
|
51
|
+
toppings: 'Ham',
|
|
52
|
+
quantity: 2,
|
|
53
|
+
itemId: itemId1
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
toppings: 'Pepperoni',
|
|
57
|
+
quantity: 1,
|
|
58
|
+
itemId: itemId2
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const pageUrl = new URL('http://example.com/repeat/pizza-order/summary')
|
|
64
|
+
|
|
65
|
+
const request = buildFormContextRequest({
|
|
66
|
+
method: 'get',
|
|
67
|
+
url: pageUrl,
|
|
68
|
+
path: pageUrl.pathname,
|
|
69
|
+
params: {
|
|
70
|
+
path: 'pizza-order',
|
|
71
|
+
slug: 'repeat'
|
|
72
|
+
},
|
|
73
|
+
query: {},
|
|
74
|
+
app: { model }
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const context = model.getFormContext(request, state)
|
|
78
|
+
|
|
79
|
+
const testDetailItemField: DetailItemField = {
|
|
80
|
+
name: 'exampleField',
|
|
81
|
+
label: 'Example Field',
|
|
82
|
+
href: '/example-field',
|
|
83
|
+
title: 'Example Field Title',
|
|
84
|
+
field: dummyField,
|
|
85
|
+
value: 'Example Value'
|
|
86
|
+
} as DetailItemField
|
|
87
|
+
|
|
88
|
+
const testDetailItemField2: DetailItemField = {
|
|
89
|
+
name: 'exampleField2',
|
|
90
|
+
label: 'Example Field 2',
|
|
91
|
+
href: '/example-field-2',
|
|
92
|
+
title: 'Example Field 2 Title',
|
|
93
|
+
field: dummyField,
|
|
94
|
+
value: 'Example Value 2'
|
|
95
|
+
} as DetailItemField
|
|
96
|
+
|
|
97
|
+
const testDetailItemRepeat: DetailItemRepeat = {
|
|
98
|
+
name: 'exampleRepeat',
|
|
99
|
+
label: 'Example Repeat',
|
|
100
|
+
href: '/example-repeat',
|
|
101
|
+
title: 'Example Repeat Title',
|
|
102
|
+
value: 'Example Repeat Value',
|
|
103
|
+
subItems: [
|
|
104
|
+
[
|
|
105
|
+
{
|
|
106
|
+
name: 'subItem1_1',
|
|
107
|
+
label: 'Sub Item 1 1',
|
|
108
|
+
field: dummyField,
|
|
109
|
+
href: '/sub-item-1-1',
|
|
110
|
+
title: 'Sub Item 1 1 Title',
|
|
111
|
+
value: 'Sub Item 1 1 Value'
|
|
112
|
+
} as DetailItemField,
|
|
113
|
+
{
|
|
114
|
+
name: 'subItem1_2',
|
|
115
|
+
label: 'Sub Item 1 2',
|
|
116
|
+
field: dummyField,
|
|
117
|
+
href: '/sub-item-1-2',
|
|
118
|
+
title: 'Sub Item 1 2 Title',
|
|
119
|
+
value: 'Sub Item 1 2 Value'
|
|
120
|
+
} as DetailItemField
|
|
121
|
+
],
|
|
122
|
+
[
|
|
123
|
+
{
|
|
124
|
+
name: 'subItem2_1',
|
|
125
|
+
label: 'Sub Item 2 1',
|
|
126
|
+
field: dummyField,
|
|
127
|
+
href: '/sub-item-2-1',
|
|
128
|
+
title: 'Sub Item 2 1 Title',
|
|
129
|
+
value: 'Sub Item 2 1 Value'
|
|
130
|
+
} as DetailItemField
|
|
131
|
+
]
|
|
132
|
+
]
|
|
133
|
+
} as DetailItemRepeat
|
|
134
|
+
|
|
135
|
+
const fileState: FileState = {
|
|
136
|
+
uploadId: '123',
|
|
137
|
+
status: {
|
|
138
|
+
form: {
|
|
139
|
+
file: {
|
|
140
|
+
fileId: '123-456-789',
|
|
141
|
+
contentLength: 1,
|
|
142
|
+
filename: 'foobar.txt',
|
|
143
|
+
fileStatus: FileStatus.complete
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
uploadStatus: UploadStatus.ready,
|
|
147
|
+
numberOfRejectedFiles: 0,
|
|
148
|
+
metadata: {
|
|
149
|
+
retrievalKey: '123'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const fileState2: FileState = {
|
|
155
|
+
uploadId: '456',
|
|
156
|
+
status: {
|
|
157
|
+
form: {
|
|
158
|
+
file: {
|
|
159
|
+
fileId: '456-789-123',
|
|
160
|
+
contentLength: 1,
|
|
161
|
+
filename: 'bazbuzz.txt',
|
|
162
|
+
fileStatus: FileStatus.complete
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
uploadStatus: UploadStatus.ready,
|
|
166
|
+
numberOfRejectedFiles: 0,
|
|
167
|
+
metadata: {
|
|
168
|
+
retrievalKey: '456'
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const testDetailItemFile1: DetailItemField = Object.create(
|
|
174
|
+
FileUploadField.prototype
|
|
175
|
+
)
|
|
176
|
+
Object.assign(testDetailItemFile1, {
|
|
177
|
+
name: 'exampleFile1',
|
|
178
|
+
label: 'Example File Field',
|
|
179
|
+
href: '/example-file',
|
|
180
|
+
title: 'Example File Field Title',
|
|
181
|
+
field: testDetailItemFile1,
|
|
182
|
+
value: 'Example File Value',
|
|
183
|
+
state: {
|
|
184
|
+
exampleFile1: [fileState, fileState2]
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const items: DetailItem[] = [
|
|
189
|
+
testDetailItemField,
|
|
190
|
+
testDetailItemField2,
|
|
191
|
+
testDetailItemRepeat,
|
|
192
|
+
testDetailItemFile1
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
describe('Adapter v1 formatter', () => {
|
|
196
|
+
beforeEach(() => {
|
|
197
|
+
jest.clearAllMocks()
|
|
198
|
+
jest.useFakeTimers()
|
|
199
|
+
jest.setSystemTime(new Date('2024-01-15T10:30:00.000Z'))
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
afterEach(() => {
|
|
203
|
+
jest.useRealTimers()
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('should return the adapter v1 output with complete formMetadata', () => {
|
|
207
|
+
const formMetadata: FormMetadata = {
|
|
208
|
+
id: 'form-123',
|
|
209
|
+
slug: 'test-form',
|
|
210
|
+
title: 'Test Form',
|
|
211
|
+
notificationEmail: 'test@example.com'
|
|
212
|
+
} as FormMetadata
|
|
213
|
+
|
|
214
|
+
const formStatus = {
|
|
215
|
+
isPreview: false,
|
|
216
|
+
state: FormStatus.Live
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const body = format(
|
|
220
|
+
context,
|
|
221
|
+
items,
|
|
222
|
+
model,
|
|
223
|
+
submitResponse,
|
|
224
|
+
formStatus,
|
|
225
|
+
formMetadata
|
|
226
|
+
)
|
|
227
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
228
|
+
|
|
229
|
+
expect(parsedBody.meta).toEqual({
|
|
230
|
+
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
231
|
+
timestamp: '2024-01-15T10:30:00.000Z',
|
|
232
|
+
referenceNumber: 'foobar',
|
|
233
|
+
formName: definition.name,
|
|
234
|
+
formId: 'form-123',
|
|
235
|
+
formSlug: 'test-form',
|
|
236
|
+
status: FormStatus.Live,
|
|
237
|
+
isPreview: false,
|
|
238
|
+
notificationEmail: 'test@example.com'
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
expect(parsedBody.data).toEqual({
|
|
242
|
+
main: {
|
|
243
|
+
exampleField: 'hello world',
|
|
244
|
+
exampleField2: 'hello world'
|
|
245
|
+
},
|
|
246
|
+
repeaters: {
|
|
247
|
+
exampleRepeat: [
|
|
248
|
+
{
|
|
249
|
+
subItem1_1: 'hello world',
|
|
250
|
+
subItem1_2: 'hello world'
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
subItem2_1: 'hello world'
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
files: {
|
|
258
|
+
exampleFile1: [
|
|
259
|
+
{
|
|
260
|
+
fileId: '123-456-789',
|
|
261
|
+
userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
fileId: '456-789-123',
|
|
265
|
+
userDownloadLink: 'https://forms-designer/file-download/456-789-123'
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('should handle preview form status correctly', () => {
|
|
273
|
+
const formMetadata: FormMetadata = {
|
|
274
|
+
id: 'form-123',
|
|
275
|
+
slug: 'test-form',
|
|
276
|
+
title: 'Test Form',
|
|
277
|
+
notificationEmail: 'test@example.com'
|
|
278
|
+
} as FormMetadata
|
|
279
|
+
|
|
280
|
+
const formStatus = {
|
|
281
|
+
isPreview: true,
|
|
282
|
+
state: FormStatus.Draft
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const body = format(
|
|
286
|
+
context,
|
|
287
|
+
items,
|
|
288
|
+
model,
|
|
289
|
+
submitResponse,
|
|
290
|
+
formStatus,
|
|
291
|
+
formMetadata
|
|
292
|
+
)
|
|
293
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
294
|
+
|
|
295
|
+
expect(parsedBody.meta.status).toBe(FormStatus.Draft)
|
|
296
|
+
expect(parsedBody.meta.isPreview).toBe(true)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it('should handle missing formMetadata with empty strings', () => {
|
|
300
|
+
const formStatus = {
|
|
301
|
+
isPreview: false,
|
|
302
|
+
state: FormStatus.Live
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
306
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
307
|
+
|
|
308
|
+
expect(parsedBody.meta.formId).toBe('')
|
|
309
|
+
expect(parsedBody.meta.formSlug).toBe('')
|
|
310
|
+
expect(parsedBody.meta.notificationEmail).toBe('')
|
|
311
|
+
expect(parsedBody.meta.formName).toBe(definition.name)
|
|
312
|
+
expect(parsedBody.meta.referenceNumber).toBe('foobar')
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('should handle partial formMetadata', () => {
|
|
316
|
+
const formMetadata: FormMetadata = {
|
|
317
|
+
id: 'form-456',
|
|
318
|
+
slug: 'partial-form',
|
|
319
|
+
title: 'Partial Form'
|
|
320
|
+
} as FormMetadata
|
|
321
|
+
|
|
322
|
+
const formStatus = {
|
|
323
|
+
isPreview: true,
|
|
324
|
+
state: FormStatus.Draft
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const body = format(
|
|
328
|
+
context,
|
|
329
|
+
items,
|
|
330
|
+
model,
|
|
331
|
+
submitResponse,
|
|
332
|
+
formStatus,
|
|
333
|
+
formMetadata
|
|
334
|
+
)
|
|
335
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
336
|
+
|
|
337
|
+
expect(parsedBody.meta.formId).toBe('form-456')
|
|
338
|
+
expect(parsedBody.meta.formSlug).toBe('partial-form')
|
|
339
|
+
expect(parsedBody.meta.notificationEmail).toBe('')
|
|
340
|
+
expect(parsedBody.meta.status).toBe(FormStatus.Draft)
|
|
341
|
+
expect(parsedBody.meta.isPreview).toBe(true)
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('should use correct schema version', () => {
|
|
345
|
+
const formStatus = {
|
|
346
|
+
isPreview: false,
|
|
347
|
+
state: FormStatus.Live
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
351
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
352
|
+
|
|
353
|
+
expect(parsedBody.meta.schemaVersion).toBe(
|
|
354
|
+
FormAdapterSubmissionSchemaVersion.V1
|
|
355
|
+
)
|
|
356
|
+
expect(parsedBody.meta.schemaVersion).toBe(1)
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it('should generate valid timestamp', () => {
|
|
360
|
+
const formStatus = {
|
|
361
|
+
isPreview: false,
|
|
362
|
+
state: FormStatus.Live
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
366
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
367
|
+
|
|
368
|
+
expect(parsedBody.meta.timestamp).toBe('2024-01-15T10:30:00.000Z')
|
|
369
|
+
expect(typeof parsedBody.meta.timestamp).toBe('string')
|
|
370
|
+
|
|
371
|
+
expect(new Date(parsedBody.meta.timestamp)).toEqual(
|
|
372
|
+
new Date('2024-01-15T10:30:00.000Z')
|
|
373
|
+
)
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it('should handle empty items array', () => {
|
|
377
|
+
const formStatus = {
|
|
378
|
+
isPreview: false,
|
|
379
|
+
state: FormStatus.Live
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const body = format(context, [], model, submitResponse, formStatus)
|
|
383
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
384
|
+
|
|
385
|
+
expect(parsedBody.data.main).toEqual({})
|
|
386
|
+
expect(parsedBody.data.repeaters).toEqual({})
|
|
387
|
+
expect(parsedBody.data.files).toEqual({})
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
it('should handle different form statuses', () => {
|
|
391
|
+
const testCases = [
|
|
392
|
+
{
|
|
393
|
+
isPreview: false,
|
|
394
|
+
state: FormStatus.Live,
|
|
395
|
+
expectedStatus: FormStatus.Live
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
isPreview: true,
|
|
399
|
+
state: FormStatus.Draft,
|
|
400
|
+
expectedStatus: FormStatus.Draft
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
isPreview: true,
|
|
404
|
+
state: FormStatus.Live,
|
|
405
|
+
expectedStatus: FormStatus.Draft
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
|
|
409
|
+
testCases.forEach(({ isPreview, state, expectedStatus }) => {
|
|
410
|
+
const formStatus = { isPreview, state }
|
|
411
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
412
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
413
|
+
|
|
414
|
+
expect(parsedBody.meta.status).toBe(expectedStatus)
|
|
415
|
+
expect(parsedBody.meta.isPreview).toBe(isPreview)
|
|
416
|
+
})
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
it('should return valid JSON string', () => {
|
|
420
|
+
const formStatus = {
|
|
421
|
+
isPreview: false,
|
|
422
|
+
state: FormStatus.Live
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
426
|
+
|
|
427
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
428
|
+
expect(() => JSON.parse(body)).not.toThrow()
|
|
429
|
+
expect(typeof body).toBe('string')
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('should handle formMetadata with only id', () => {
|
|
433
|
+
const formMetadata: FormMetadata = {
|
|
434
|
+
id: 'only-id-form'
|
|
435
|
+
} as FormMetadata
|
|
436
|
+
|
|
437
|
+
const formStatus = {
|
|
438
|
+
isPreview: false,
|
|
439
|
+
state: FormStatus.Live
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const body = format(
|
|
443
|
+
context,
|
|
444
|
+
items,
|
|
445
|
+
model,
|
|
446
|
+
submitResponse,
|
|
447
|
+
formStatus,
|
|
448
|
+
formMetadata
|
|
449
|
+
)
|
|
450
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
451
|
+
|
|
452
|
+
expect(parsedBody.meta.formId).toBe('only-id-form')
|
|
453
|
+
expect(parsedBody.meta.formSlug).toBe('')
|
|
454
|
+
expect(parsedBody.meta.notificationEmail).toBe('')
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
it('should handle formMetadata with only slug', () => {
|
|
458
|
+
const formMetadata: FormMetadata = {
|
|
459
|
+
slug: 'only-slug-form'
|
|
460
|
+
} as FormMetadata
|
|
461
|
+
|
|
462
|
+
const formStatus = {
|
|
463
|
+
isPreview: false,
|
|
464
|
+
state: FormStatus.Live
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const body = format(
|
|
468
|
+
context,
|
|
469
|
+
items,
|
|
470
|
+
model,
|
|
471
|
+
submitResponse,
|
|
472
|
+
formStatus,
|
|
473
|
+
formMetadata
|
|
474
|
+
)
|
|
475
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
476
|
+
|
|
477
|
+
expect(parsedBody.meta.formId).toBe('')
|
|
478
|
+
expect(parsedBody.meta.formSlug).toBe('only-slug-form')
|
|
479
|
+
expect(parsedBody.meta.notificationEmail).toBe('')
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
it('should handle formMetadata with only notificationEmail', () => {
|
|
483
|
+
const formMetadata: FormMetadata = {
|
|
484
|
+
notificationEmail: 'only-email@example.com'
|
|
485
|
+
} as FormMetadata
|
|
486
|
+
|
|
487
|
+
const formStatus = {
|
|
488
|
+
isPreview: false,
|
|
489
|
+
state: FormStatus.Live
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const body = format(
|
|
493
|
+
context,
|
|
494
|
+
items,
|
|
495
|
+
model,
|
|
496
|
+
submitResponse,
|
|
497
|
+
formStatus,
|
|
498
|
+
formMetadata
|
|
499
|
+
)
|
|
500
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
501
|
+
|
|
502
|
+
expect(parsedBody.meta.formId).toBe('')
|
|
503
|
+
expect(parsedBody.meta.formSlug).toBe('')
|
|
504
|
+
expect(parsedBody.meta.notificationEmail).toBe('only-email@example.com')
|
|
505
|
+
})
|
|
506
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type FormMetadata,
|
|
3
|
+
type SubmitResponsePayload
|
|
4
|
+
} from '@defra/forms-model'
|
|
5
|
+
|
|
6
|
+
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
|
|
7
|
+
import { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
8
|
+
import { type DetailItem } from '~/src/server/plugins/engine/models/types.js'
|
|
9
|
+
import { format as machineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
|
|
10
|
+
import {
|
|
11
|
+
FormAdapterSubmissionSchemaVersion,
|
|
12
|
+
type FormAdapterSubmissionMessageData,
|
|
13
|
+
type FormAdapterSubmissionMessagePayload,
|
|
14
|
+
type FormContext
|
|
15
|
+
} from '~/src/server/plugins/engine/types.js'
|
|
16
|
+
import { FormStatus } from '~/src/server/routes/types.js'
|
|
17
|
+
|
|
18
|
+
export function format(
|
|
19
|
+
context: FormContext,
|
|
20
|
+
items: DetailItem[],
|
|
21
|
+
model: FormModel,
|
|
22
|
+
submitResponse: SubmitResponsePayload,
|
|
23
|
+
formStatus: ReturnType<typeof checkFormStatus>,
|
|
24
|
+
formMetadata?: FormMetadata
|
|
25
|
+
): string {
|
|
26
|
+
const v2DataString = machineV2(
|
|
27
|
+
context,
|
|
28
|
+
items,
|
|
29
|
+
model,
|
|
30
|
+
submitResponse,
|
|
31
|
+
formStatus
|
|
32
|
+
)
|
|
33
|
+
const v2DataParsed = JSON.parse(v2DataString) as {
|
|
34
|
+
data: FormAdapterSubmissionMessageData
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const payload: FormAdapterSubmissionMessagePayload = {
|
|
38
|
+
meta: {
|
|
39
|
+
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
40
|
+
timestamp: new Date(),
|
|
41
|
+
referenceNumber: context.referenceNumber,
|
|
42
|
+
formName: model.name,
|
|
43
|
+
formId: formMetadata?.id ?? '',
|
|
44
|
+
formSlug: formMetadata?.slug ?? '',
|
|
45
|
+
status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
|
|
46
|
+
isPreview: formStatus.isPreview,
|
|
47
|
+
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
48
|
+
},
|
|
49
|
+
data: v2DataParsed.data
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return JSON.stringify(payload)
|
|
53
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type FormMetadata,
|
|
3
|
+
type SubmitResponsePayload
|
|
4
|
+
} from '@defra/forms-model'
|
|
2
5
|
import { addDays, format as dateFormat } from 'date-fns'
|
|
3
6
|
|
|
4
7
|
import { config } from '~/src/config/index.js'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
getAnswer
|
|
8
|
-
} from '~/src/server/plugins/engine/components/helpers.js'
|
|
8
|
+
import { getAnswer } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
9
|
+
import { escapeMarkdown } from '~/src/server/plugins/engine/components/helpers/index.js'
|
|
9
10
|
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
|
|
10
11
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
11
12
|
import { type DetailItem } from '~/src/server/plugins/engine/models/types.js'
|
|
@@ -18,7 +19,8 @@ export function format(
|
|
|
18
19
|
items: DetailItem[],
|
|
19
20
|
model: FormModel,
|
|
20
21
|
submitResponse: SubmitResponsePayload,
|
|
21
|
-
formStatus: ReturnType<typeof checkFormStatus
|
|
22
|
+
formStatus: ReturnType<typeof checkFormStatus>,
|
|
23
|
+
_formMetadata?: FormMetadata
|
|
22
24
|
) {
|
|
23
25
|
const { files } = submitResponse.result
|
|
24
26
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type FormMetadata,
|
|
3
|
+
type SubmitResponsePayload
|
|
4
|
+
} from '@defra/forms-model'
|
|
2
5
|
|
|
3
6
|
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
|
|
4
7
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
5
8
|
import { type DetailItem } from '~/src/server/plugins/engine/models/types.js'
|
|
9
|
+
import { format as formatAdapterV1 } from '~/src/server/plugins/engine/outputFormatters/adapter/v1.js'
|
|
6
10
|
import { format as formatHumanV1 } from '~/src/server/plugins/engine/outputFormatters/human/v1.js'
|
|
7
11
|
import { format as formatMachineV1 } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'
|
|
8
12
|
import { format as formatMachineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
|
|
@@ -13,12 +17,13 @@ type Formatter = (
|
|
|
13
17
|
items: DetailItem[],
|
|
14
18
|
model: FormModel,
|
|
15
19
|
submitResponse: SubmitResponsePayload,
|
|
16
|
-
formStatus: ReturnType<typeof checkFormStatus
|
|
20
|
+
formStatus: ReturnType<typeof checkFormStatus>,
|
|
21
|
+
formMetadata?: FormMetadata
|
|
17
22
|
) => string
|
|
18
23
|
|
|
19
24
|
const formatters: Record<
|
|
20
25
|
string,
|
|
21
|
-
Record<string, Formatter | undefined> | undefined
|
|
26
|
+
Record<string, Formatter | typeof formatAdapterV1 | undefined> | undefined
|
|
22
27
|
> = {
|
|
23
28
|
human: {
|
|
24
29
|
'1': formatHumanV1
|
|
@@ -26,6 +31,9 @@ const formatters: Record<
|
|
|
26
31
|
machine: {
|
|
27
32
|
'1': formatMachineV1,
|
|
28
33
|
'2': formatMachineV2
|
|
34
|
+
},
|
|
35
|
+
adapter: {
|
|
36
|
+
'1': formatAdapterV1
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
2
|
|
|
3
3
|
import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
|
|
4
|
-
import { type Field } from '~/src/server/plugins/engine/components/helpers.js'
|
|
4
|
+
import { type Field } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
5
5
|
import { FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
6
6
|
import {
|
|
7
7
|
type DetailItem,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type FormMetadata,
|
|
3
|
+
type SubmitResponsePayload
|
|
4
|
+
} from '@defra/forms-model'
|
|
2
5
|
|
|
3
6
|
import { config } from '~/src/config/index.js'
|
|
4
|
-
import { getAnswer } from '~/src/server/plugins/engine/components/helpers.js'
|
|
7
|
+
import { getAnswer } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
5
8
|
import { FileUploadField } from '~/src/server/plugins/engine/components/index.js'
|
|
6
9
|
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
|
|
7
10
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
@@ -19,7 +22,8 @@ export function format(
|
|
|
19
22
|
items: DetailItem[],
|
|
20
23
|
model: FormModel,
|
|
21
24
|
_submitResponse: SubmitResponsePayload,
|
|
22
|
-
_formStatus: ReturnType<typeof checkFormStatus
|
|
25
|
+
_formStatus: ReturnType<typeof checkFormStatus>,
|
|
26
|
+
_formMetadata?: FormMetadata
|
|
23
27
|
) {
|
|
24
28
|
const now = new Date()
|
|
25
29
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
2
|
|
|
3
3
|
import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
|
|
4
|
-
import { type Field } from '~/src/server/plugins/engine/components/helpers.js'
|
|
4
|
+
import { type Field } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
5
5
|
import { FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
6
6
|
import {
|
|
7
7
|
type DetailItem,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from '~/src/server/plugins/engine/pageControllers/FileUploadPageController.js'
|
|
16
16
|
import { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'
|
|
17
17
|
import { serverWithSaveAndReturn } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
|
|
18
|
-
import * as pageHelpers from '~/src/server/plugins/engine/pageControllers/helpers.js'
|
|
18
|
+
import * as pageHelpers from '~/src/server/plugins/engine/pageControllers/helpers/index.js'
|
|
19
19
|
import * as uploadService from '~/src/server/plugins/engine/services/uploadService.js'
|
|
20
20
|
import {
|
|
21
21
|
FileStatus,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from '~/src/server/plugins/engine/helpers.js'
|
|
16
16
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
17
17
|
import { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'
|
|
18
|
-
import { getProxyUrlForLocalDevelopment } from '~/src/server/plugins/engine/pageControllers/helpers.js'
|
|
18
|
+
import { getProxyUrlForLocalDevelopment } from '~/src/server/plugins/engine/pageControllers/helpers/index.js'
|
|
19
19
|
import {
|
|
20
20
|
getUploadStatus,
|
|
21
21
|
initiateUpload
|