@defra/forms-engine-plugin 3.0.0 → 3.0.1
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/models/FormModel.d.ts +2 -0
- package/.server/server/plugins/engine/models/FormModel.js +4 -1
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +4 -0
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +25 -0
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +7 -6
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/routes/index.js +3 -1
- package/.server/server/plugins/engine/routes/index.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.js +3 -2
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +3 -1
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/package.json +2 -2
- package/src/server/plugins/engine/models/FormModel.test.ts +64 -0
- package/src/server/plugins/engine/models/FormModel.ts +5 -2
- package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +446 -13
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +37 -0
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +8 -6
- package/src/server/plugins/engine/routes/index.ts +3 -1
- package/src/server/plugins/engine/types/schema.test.ts +40 -0
- package/src/server/plugins/engine/types/schema.ts +3 -1
- package/src/server/plugins/engine/types.ts +3 -0
|
@@ -141,6 +141,21 @@ describe('FormModel', () => {
|
|
|
141
141
|
expect(model.schemaVersion).toBe(SchemaVersion.V1)
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
+
it('sets versionNumber from options', () => {
|
|
145
|
+
const model = new FormModel(definition, {
|
|
146
|
+
basePath: 'test',
|
|
147
|
+
versionNumber: 42
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
expect(model.versionNumber).toBe(42)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('sets versionNumber to undefined when not provided', () => {
|
|
154
|
+
const model = new FormModel(definition, { basePath: 'test' })
|
|
155
|
+
|
|
156
|
+
expect(model.versionNumber).toBeUndefined()
|
|
157
|
+
})
|
|
158
|
+
|
|
144
159
|
it.each([
|
|
145
160
|
{
|
|
146
161
|
input: undefined,
|
|
@@ -329,6 +344,55 @@ describe('FormModel', () => {
|
|
|
329
344
|
)
|
|
330
345
|
})
|
|
331
346
|
|
|
347
|
+
it('includes submittedVersionNumber in context when versionNumber is set', () => {
|
|
348
|
+
const formModel = new FormModel(fieldsRequiredDefinition, {
|
|
349
|
+
basePath: '/components',
|
|
350
|
+
versionNumber: 123
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
const state = {
|
|
354
|
+
$$__referenceNumber: 'foobar'
|
|
355
|
+
}
|
|
356
|
+
const pageUrl = new URL('http://example.com/components/fields-required')
|
|
357
|
+
|
|
358
|
+
const request: FormContextRequest = buildFormContextRequest({
|
|
359
|
+
method: 'get',
|
|
360
|
+
query: {},
|
|
361
|
+
path: pageUrl.pathname,
|
|
362
|
+
params: { path: 'components', slug: 'fields-required' },
|
|
363
|
+
url: pageUrl,
|
|
364
|
+
app: { model: formModel }
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
const context = formModel.getFormContext(request, state)
|
|
368
|
+
|
|
369
|
+
expect(context.submittedVersionNumber).toBe(123)
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it('sets submittedVersionNumber to undefined when versionNumber is not set', () => {
|
|
373
|
+
const formModel = new FormModel(fieldsRequiredDefinition, {
|
|
374
|
+
basePath: '/components'
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
const state = {
|
|
378
|
+
$$__referenceNumber: 'foobar'
|
|
379
|
+
}
|
|
380
|
+
const pageUrl = new URL('http://example.com/components/fields-required')
|
|
381
|
+
|
|
382
|
+
const request: FormContextRequest = buildFormContextRequest({
|
|
383
|
+
method: 'get',
|
|
384
|
+
query: {},
|
|
385
|
+
path: pageUrl.pathname,
|
|
386
|
+
params: { path: 'components', slug: 'fields-required' },
|
|
387
|
+
url: pageUrl,
|
|
388
|
+
app: { model: formModel }
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const context = formModel.getFormContext(request, state)
|
|
392
|
+
|
|
393
|
+
expect(context.submittedVersionNumber).toBeUndefined()
|
|
394
|
+
})
|
|
395
|
+
|
|
332
396
|
it('redirects to the page if the list field (radio) is invalidated due to list item conditions', () => {
|
|
333
397
|
const formModel = new FormModel(conditionsListDefinition, {
|
|
334
398
|
basePath: '/conditional-list-items'
|
|
@@ -76,6 +76,7 @@ export class FormModel {
|
|
|
76
76
|
name: string
|
|
77
77
|
values: FormDefinition
|
|
78
78
|
basePath: string
|
|
79
|
+
versionNumber?: number
|
|
79
80
|
conditions: Partial<Record<string, ExecutableCondition>>
|
|
80
81
|
pages: PageControllerClass[]
|
|
81
82
|
services: Services
|
|
@@ -94,7 +95,7 @@ export class FormModel {
|
|
|
94
95
|
|
|
95
96
|
constructor(
|
|
96
97
|
def: typeof this.def,
|
|
97
|
-
options: { basePath: string },
|
|
98
|
+
options: { basePath: string; versionNumber?: number },
|
|
98
99
|
services: Services = defaultServices,
|
|
99
100
|
controllers?: Record<string, typeof PageController>
|
|
100
101
|
) {
|
|
@@ -148,6 +149,7 @@ export class FormModel {
|
|
|
148
149
|
this.name = def.name ?? ''
|
|
149
150
|
this.values = result.value
|
|
150
151
|
this.basePath = options.basePath
|
|
152
|
+
this.versionNumber = options.versionNumber
|
|
151
153
|
this.conditions = {}
|
|
152
154
|
this.services = services
|
|
153
155
|
this.controllers = controllers
|
|
@@ -344,7 +346,8 @@ export class FormModel {
|
|
|
344
346
|
componentDefMap: this.componentDefMap,
|
|
345
347
|
pageMap: this.pageMap,
|
|
346
348
|
componentMap: this.componentMap,
|
|
347
|
-
referenceNumber: getReferenceNumber(state)
|
|
349
|
+
referenceNumber: getReferenceNumber(state),
|
|
350
|
+
submittedVersionNumber: this.versionNumber
|
|
348
351
|
}
|
|
349
352
|
|
|
350
353
|
// Validate current page
|
|
@@ -11,7 +11,10 @@ import {
|
|
|
11
11
|
type DetailItemField,
|
|
12
12
|
type DetailItemRepeat
|
|
13
13
|
} from '~/src/server/plugins/engine/models/types.js'
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
format,
|
|
16
|
+
getVersionMetadata
|
|
17
|
+
} from '~/src/server/plugins/engine/outputFormatters/adapter/v1.js'
|
|
15
18
|
import { buildFormContextRequest } from '~/src/server/plugins/engine/pageControllers/__stubs__/request.js'
|
|
16
19
|
import { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/index.js'
|
|
17
20
|
import {
|
|
@@ -207,7 +210,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
207
210
|
})
|
|
208
211
|
|
|
209
212
|
it('should return the adapter v1 output with complete formMetadata', () => {
|
|
210
|
-
const formMetadata: FormMetadata = {
|
|
213
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
211
214
|
id: 'form-123',
|
|
212
215
|
slug: 'test-form',
|
|
213
216
|
title: 'Test Form',
|
|
@@ -225,7 +228,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
225
228
|
model,
|
|
226
229
|
submitResponse,
|
|
227
230
|
formStatus,
|
|
228
|
-
formMetadata
|
|
231
|
+
formMetadata as FormMetadata
|
|
229
232
|
)
|
|
230
233
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
231
234
|
|
|
@@ -284,7 +287,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
284
287
|
})
|
|
285
288
|
|
|
286
289
|
it('should handle preview form status correctly', () => {
|
|
287
|
-
const formMetadata: FormMetadata = {
|
|
290
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
288
291
|
id: 'form-123',
|
|
289
292
|
slug: 'test-form',
|
|
290
293
|
title: 'Test Form',
|
|
@@ -302,7 +305,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
302
305
|
model,
|
|
303
306
|
submitResponse,
|
|
304
307
|
formStatus,
|
|
305
|
-
formMetadata
|
|
308
|
+
formMetadata as FormMetadata
|
|
306
309
|
)
|
|
307
310
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
308
311
|
|
|
@@ -327,7 +330,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
327
330
|
})
|
|
328
331
|
|
|
329
332
|
it('should handle partial formMetadata', () => {
|
|
330
|
-
const formMetadata: FormMetadata = {
|
|
333
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
331
334
|
id: 'form-456',
|
|
332
335
|
slug: 'partial-form',
|
|
333
336
|
title: 'Partial Form'
|
|
@@ -344,7 +347,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
344
347
|
model,
|
|
345
348
|
submitResponse,
|
|
346
349
|
formStatus,
|
|
347
|
-
formMetadata
|
|
350
|
+
formMetadata as FormMetadata
|
|
348
351
|
)
|
|
349
352
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
350
353
|
|
|
@@ -452,7 +455,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
452
455
|
})
|
|
453
456
|
|
|
454
457
|
it('should handle formMetadata with only id', () => {
|
|
455
|
-
const formMetadata: FormMetadata = {
|
|
458
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
456
459
|
id: 'only-id-form'
|
|
457
460
|
} as FormMetadata
|
|
458
461
|
|
|
@@ -467,7 +470,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
467
470
|
model,
|
|
468
471
|
submitResponse,
|
|
469
472
|
formStatus,
|
|
470
|
-
formMetadata
|
|
473
|
+
formMetadata as FormMetadata
|
|
471
474
|
)
|
|
472
475
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
473
476
|
|
|
@@ -477,7 +480,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
477
480
|
})
|
|
478
481
|
|
|
479
482
|
it('should handle formMetadata with only slug', () => {
|
|
480
|
-
const formMetadata: FormMetadata = {
|
|
483
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
481
484
|
slug: 'only-slug-form'
|
|
482
485
|
} as FormMetadata
|
|
483
486
|
|
|
@@ -492,7 +495,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
492
495
|
model,
|
|
493
496
|
submitResponse,
|
|
494
497
|
formStatus,
|
|
495
|
-
formMetadata
|
|
498
|
+
formMetadata as FormMetadata
|
|
496
499
|
)
|
|
497
500
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
498
501
|
|
|
@@ -502,7 +505,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
502
505
|
})
|
|
503
506
|
|
|
504
507
|
it('should handle formMetadata with only notificationEmail', () => {
|
|
505
|
-
const formMetadata: FormMetadata = {
|
|
508
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
506
509
|
notificationEmail: 'only-email@example.com'
|
|
507
510
|
} as FormMetadata
|
|
508
511
|
|
|
@@ -517,7 +520,7 @@ describe('Adapter v1 formatter', () => {
|
|
|
517
520
|
model,
|
|
518
521
|
submitResponse,
|
|
519
522
|
formStatus,
|
|
520
|
-
formMetadata
|
|
523
|
+
formMetadata as FormMetadata
|
|
521
524
|
)
|
|
522
525
|
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
523
526
|
|
|
@@ -693,4 +696,434 @@ describe('Adapter v1 formatter', () => {
|
|
|
693
696
|
}
|
|
694
697
|
})
|
|
695
698
|
})
|
|
699
|
+
|
|
700
|
+
it('should handle missing versionMetadata gracefully', () => {
|
|
701
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
702
|
+
id: 'form-123',
|
|
703
|
+
slug: 'test-form',
|
|
704
|
+
title: 'Test Form',
|
|
705
|
+
notificationEmail: 'test@example.com'
|
|
706
|
+
} as FormMetadata
|
|
707
|
+
|
|
708
|
+
const formStatus = {
|
|
709
|
+
isPreview: false,
|
|
710
|
+
state: FormStatus.Live
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const body = format(
|
|
714
|
+
context,
|
|
715
|
+
items,
|
|
716
|
+
model,
|
|
717
|
+
submitResponse,
|
|
718
|
+
formStatus,
|
|
719
|
+
formMetadata as FormMetadata
|
|
720
|
+
)
|
|
721
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
722
|
+
|
|
723
|
+
expect(parsedBody.meta.versionMetadata).toBeUndefined()
|
|
724
|
+
})
|
|
725
|
+
|
|
726
|
+
describe('version metadata handling', () => {
|
|
727
|
+
it('should include versionMetadata when context has submittedVersionNumber and formMetadata has versions', () => {
|
|
728
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
729
|
+
id: 'form-123',
|
|
730
|
+
slug: 'test-form',
|
|
731
|
+
title: 'Test Form',
|
|
732
|
+
notificationEmail: 'test@example.com',
|
|
733
|
+
versions: [
|
|
734
|
+
{
|
|
735
|
+
versionNumber: 1,
|
|
736
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
versionNumber: 2,
|
|
740
|
+
createdAt: new Date('2024-01-15T00:00:00.000Z')
|
|
741
|
+
}
|
|
742
|
+
]
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const modelWithVersion = new FormModel(definition, {
|
|
746
|
+
basePath: 'test',
|
|
747
|
+
versionNumber: 2
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
const contextWithVersion = modelWithVersion.getFormContext(request, state)
|
|
751
|
+
|
|
752
|
+
const formStatus = {
|
|
753
|
+
isPreview: false,
|
|
754
|
+
state: FormStatus.Live
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const body = format(
|
|
758
|
+
contextWithVersion,
|
|
759
|
+
items,
|
|
760
|
+
modelWithVersion,
|
|
761
|
+
submitResponse,
|
|
762
|
+
formStatus,
|
|
763
|
+
formMetadata as FormMetadata
|
|
764
|
+
)
|
|
765
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
766
|
+
|
|
767
|
+
expect(parsedBody.meta.versionMetadata).toEqual({
|
|
768
|
+
versionNumber: 2,
|
|
769
|
+
createdAt: '2024-01-15T00:00:00.000Z'
|
|
770
|
+
})
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
it('should use first version as fallback when submittedVersionNumber is undefined', () => {
|
|
774
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
775
|
+
id: 'form-123',
|
|
776
|
+
slug: 'test-form',
|
|
777
|
+
title: 'Test Form',
|
|
778
|
+
notificationEmail: 'test@example.com',
|
|
779
|
+
versions: [
|
|
780
|
+
{
|
|
781
|
+
versionNumber: 1,
|
|
782
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
versionNumber: 2,
|
|
786
|
+
createdAt: new Date('2024-01-15T00:00:00.000Z')
|
|
787
|
+
}
|
|
788
|
+
]
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const formStatus = {
|
|
792
|
+
isPreview: false,
|
|
793
|
+
state: FormStatus.Live
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const body = format(
|
|
797
|
+
context,
|
|
798
|
+
items,
|
|
799
|
+
model,
|
|
800
|
+
submitResponse,
|
|
801
|
+
formStatus,
|
|
802
|
+
formMetadata as FormMetadata
|
|
803
|
+
)
|
|
804
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
805
|
+
|
|
806
|
+
expect(parsedBody.meta.versionMetadata).toEqual({
|
|
807
|
+
versionNumber: 1,
|
|
808
|
+
createdAt: '2024-01-01T00:00:00.000Z'
|
|
809
|
+
})
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
it('should not include versionMetadata when submittedVersionNumber is undefined and no versions exist', () => {
|
|
813
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
814
|
+
id: 'form-123',
|
|
815
|
+
slug: 'test-form',
|
|
816
|
+
title: 'Test Form',
|
|
817
|
+
notificationEmail: 'test@example.com'
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const formStatus = {
|
|
821
|
+
isPreview: false,
|
|
822
|
+
state: FormStatus.Live
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const body = format(
|
|
826
|
+
context,
|
|
827
|
+
items,
|
|
828
|
+
model,
|
|
829
|
+
submitResponse,
|
|
830
|
+
formStatus,
|
|
831
|
+
formMetadata as FormMetadata
|
|
832
|
+
)
|
|
833
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
834
|
+
|
|
835
|
+
expect(parsedBody.meta.versionMetadata).toBeUndefined()
|
|
836
|
+
})
|
|
837
|
+
|
|
838
|
+
it('should not include versionMetadata when submittedVersionNumber is undefined and versions array is empty', () => {
|
|
839
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
840
|
+
id: 'form-123',
|
|
841
|
+
slug: 'test-form',
|
|
842
|
+
title: 'Test Form',
|
|
843
|
+
notificationEmail: 'test@example.com',
|
|
844
|
+
versions: []
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const formStatus = {
|
|
848
|
+
isPreview: false,
|
|
849
|
+
state: FormStatus.Live
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const body = format(
|
|
853
|
+
context,
|
|
854
|
+
items,
|
|
855
|
+
model,
|
|
856
|
+
submitResponse,
|
|
857
|
+
formStatus,
|
|
858
|
+
formMetadata as FormMetadata
|
|
859
|
+
)
|
|
860
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
861
|
+
|
|
862
|
+
expect(parsedBody.meta.versionMetadata).toBeUndefined()
|
|
863
|
+
})
|
|
864
|
+
|
|
865
|
+
it('should not include versionMetadata when submittedVersionNumber does not match any version', () => {
|
|
866
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
867
|
+
id: 'form-123',
|
|
868
|
+
slug: 'test-form',
|
|
869
|
+
title: 'Test Form',
|
|
870
|
+
notificationEmail: 'test@example.com',
|
|
871
|
+
versions: [
|
|
872
|
+
{
|
|
873
|
+
versionNumber: 1,
|
|
874
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
versionNumber: 2,
|
|
878
|
+
createdAt: new Date('2024-01-15T00:00:00.000Z')
|
|
879
|
+
}
|
|
880
|
+
]
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const modelWithVersion = new FormModel(definition, {
|
|
884
|
+
basePath: 'test',
|
|
885
|
+
versionNumber: 99 // Non-existent version
|
|
886
|
+
})
|
|
887
|
+
|
|
888
|
+
const contextWithVersion = modelWithVersion.getFormContext(request, state)
|
|
889
|
+
|
|
890
|
+
const formStatus = {
|
|
891
|
+
isPreview: false,
|
|
892
|
+
state: FormStatus.Live
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
const body = format(
|
|
896
|
+
contextWithVersion,
|
|
897
|
+
items,
|
|
898
|
+
modelWithVersion,
|
|
899
|
+
submitResponse,
|
|
900
|
+
formStatus,
|
|
901
|
+
formMetadata as FormMetadata
|
|
902
|
+
)
|
|
903
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
904
|
+
|
|
905
|
+
// Should fall back to first version since submittedVersionNumber doesn't match
|
|
906
|
+
expect(parsedBody.meta.versionMetadata).toEqual({
|
|
907
|
+
versionNumber: 1,
|
|
908
|
+
createdAt: '2024-01-01T00:00:00.000Z'
|
|
909
|
+
})
|
|
910
|
+
})
|
|
911
|
+
|
|
912
|
+
it('should use first version as fallback when submittedVersionNumber does not match any version', () => {
|
|
913
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
914
|
+
id: 'form-123',
|
|
915
|
+
slug: 'test-form',
|
|
916
|
+
title: 'Test Form',
|
|
917
|
+
notificationEmail: 'test@example.com',
|
|
918
|
+
versions: [
|
|
919
|
+
{
|
|
920
|
+
versionNumber: 1,
|
|
921
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
versionNumber: 2,
|
|
925
|
+
createdAt: new Date('2024-01-15T00:00:00.000Z')
|
|
926
|
+
}
|
|
927
|
+
]
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const modelWithVersion = new FormModel(definition, {
|
|
931
|
+
basePath: 'test',
|
|
932
|
+
versionNumber: 99 // Non-existent version
|
|
933
|
+
})
|
|
934
|
+
|
|
935
|
+
const contextWithVersion = modelWithVersion.getFormContext(request, state)
|
|
936
|
+
|
|
937
|
+
const formStatus = {
|
|
938
|
+
isPreview: false,
|
|
939
|
+
state: FormStatus.Live
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const body = format(
|
|
943
|
+
contextWithVersion,
|
|
944
|
+
items,
|
|
945
|
+
modelWithVersion,
|
|
946
|
+
submitResponse,
|
|
947
|
+
formStatus,
|
|
948
|
+
formMetadata as FormMetadata
|
|
949
|
+
)
|
|
950
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
951
|
+
|
|
952
|
+
// Should fall back to first version since submittedVersionNumber doesn't match
|
|
953
|
+
expect(parsedBody.meta.versionMetadata).toEqual({
|
|
954
|
+
versionNumber: 1,
|
|
955
|
+
createdAt: '2024-01-01T00:00:00.000Z'
|
|
956
|
+
})
|
|
957
|
+
})
|
|
958
|
+
|
|
959
|
+
it('should handle single version in versions array', () => {
|
|
960
|
+
const formMetadata: Partial<FormMetadata> = {
|
|
961
|
+
id: 'form-123',
|
|
962
|
+
slug: 'test-form',
|
|
963
|
+
title: 'Test Form',
|
|
964
|
+
notificationEmail: 'test@example.com',
|
|
965
|
+
versions: [
|
|
966
|
+
{
|
|
967
|
+
versionNumber: 5,
|
|
968
|
+
createdAt: new Date('2024-02-01T00:00:00.000Z')
|
|
969
|
+
}
|
|
970
|
+
]
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const formStatus = {
|
|
974
|
+
isPreview: false,
|
|
975
|
+
state: FormStatus.Live
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
const body = format(
|
|
979
|
+
context,
|
|
980
|
+
items,
|
|
981
|
+
model,
|
|
982
|
+
submitResponse,
|
|
983
|
+
formStatus,
|
|
984
|
+
formMetadata as FormMetadata
|
|
985
|
+
)
|
|
986
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
987
|
+
|
|
988
|
+
expect(parsedBody.meta.versionMetadata).toEqual({
|
|
989
|
+
versionNumber: 5,
|
|
990
|
+
createdAt: '2024-02-01T00:00:00.000Z'
|
|
991
|
+
})
|
|
992
|
+
})
|
|
993
|
+
})
|
|
994
|
+
|
|
995
|
+
describe('getVersionMetadata', () => {
|
|
996
|
+
const mockFormMetadata: Partial<FormMetadata> = {
|
|
997
|
+
id: 'form-123',
|
|
998
|
+
slug: 'test-form',
|
|
999
|
+
title: 'Test Form',
|
|
1000
|
+
notificationEmail: 'test@example.com',
|
|
1001
|
+
versions: [
|
|
1002
|
+
{
|
|
1003
|
+
versionNumber: 1,
|
|
1004
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
versionNumber: 2,
|
|
1008
|
+
createdAt: new Date('2024-01-02T00:00:00.000Z')
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
versionNumber: 3,
|
|
1012
|
+
createdAt: new Date('2024-01-03T00:00:00.000Z')
|
|
1013
|
+
}
|
|
1014
|
+
]
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
it('should return undefined when no form metadata provided', () => {
|
|
1018
|
+
const result = getVersionMetadata(1, undefined)
|
|
1019
|
+
expect(result).toBeUndefined()
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
it('should return undefined when form metadata has no versions', () => {
|
|
1023
|
+
const formMetadataWithoutVersions: Partial<FormMetadata> = {
|
|
1024
|
+
...mockFormMetadata,
|
|
1025
|
+
versions: undefined
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
const result = getVersionMetadata(
|
|
1029
|
+
1,
|
|
1030
|
+
formMetadataWithoutVersions as FormMetadata
|
|
1031
|
+
)
|
|
1032
|
+
expect(result).toBeUndefined()
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1035
|
+
it('should return undefined when versions array is empty', () => {
|
|
1036
|
+
const formMetadataWithEmptyVersions: Partial<FormMetadata> = {
|
|
1037
|
+
...mockFormMetadata,
|
|
1038
|
+
versions: []
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const result = getVersionMetadata(
|
|
1042
|
+
1,
|
|
1043
|
+
formMetadataWithEmptyVersions as FormMetadata
|
|
1044
|
+
)
|
|
1045
|
+
expect(result).toBeUndefined()
|
|
1046
|
+
})
|
|
1047
|
+
|
|
1048
|
+
it('should return specific version when submittedVersionNumber matches', () => {
|
|
1049
|
+
const result = getVersionMetadata(2, mockFormMetadata as FormMetadata)
|
|
1050
|
+
expect(result).toEqual({
|
|
1051
|
+
versionNumber: 2,
|
|
1052
|
+
createdAt: new Date('2024-01-02T00:00:00.000Z')
|
|
1053
|
+
})
|
|
1054
|
+
})
|
|
1055
|
+
|
|
1056
|
+
it('should return first version when submittedVersionNumber not found', () => {
|
|
1057
|
+
const result = getVersionMetadata(999, mockFormMetadata as FormMetadata)
|
|
1058
|
+
expect(result).toEqual({
|
|
1059
|
+
versionNumber: 1,
|
|
1060
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1061
|
+
})
|
|
1062
|
+
})
|
|
1063
|
+
|
|
1064
|
+
it('should return first version when no submittedVersionNumber provided', () => {
|
|
1065
|
+
const result = getVersionMetadata(
|
|
1066
|
+
undefined,
|
|
1067
|
+
mockFormMetadata as FormMetadata
|
|
1068
|
+
)
|
|
1069
|
+
expect(result).toEqual({
|
|
1070
|
+
versionNumber: 1,
|
|
1071
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1072
|
+
})
|
|
1073
|
+
})
|
|
1074
|
+
|
|
1075
|
+
it('should handle single version in versions array', () => {
|
|
1076
|
+
const singleVersionMetadata: Partial<FormMetadata> = {
|
|
1077
|
+
...mockFormMetadata,
|
|
1078
|
+
versions: [
|
|
1079
|
+
{
|
|
1080
|
+
versionNumber: 5,
|
|
1081
|
+
createdAt: new Date('2024-02-01T00:00:00.000Z')
|
|
1082
|
+
}
|
|
1083
|
+
]
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
const result = getVersionMetadata(
|
|
1087
|
+
undefined,
|
|
1088
|
+
singleVersionMetadata as FormMetadata
|
|
1089
|
+
)
|
|
1090
|
+
expect(result).toEqual({
|
|
1091
|
+
versionNumber: 5,
|
|
1092
|
+
createdAt: new Date('2024-02-01T00:00:00.000Z')
|
|
1093
|
+
})
|
|
1094
|
+
})
|
|
1095
|
+
|
|
1096
|
+
it('should return correct version when submittedVersionNumber is 0', () => {
|
|
1097
|
+
const metadataWithVersionZero: Partial<FormMetadata> = {
|
|
1098
|
+
...mockFormMetadata,
|
|
1099
|
+
versions: [
|
|
1100
|
+
{
|
|
1101
|
+
versionNumber: 0,
|
|
1102
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
versionNumber: 1,
|
|
1106
|
+
createdAt: new Date('2024-01-02T00:00:00.000Z')
|
|
1107
|
+
}
|
|
1108
|
+
]
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
const result = getVersionMetadata(
|
|
1112
|
+
0,
|
|
1113
|
+
metadataWithVersionZero as FormMetadata
|
|
1114
|
+
)
|
|
1115
|
+
expect(result).toEqual({
|
|
1116
|
+
versionNumber: 0,
|
|
1117
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1118
|
+
})
|
|
1119
|
+
})
|
|
1120
|
+
|
|
1121
|
+
it('should handle negative submittedVersionNumber by falling back to first version', () => {
|
|
1122
|
+
const result = getVersionMetadata(-1, mockFormMetadata as FormMetadata)
|
|
1123
|
+
expect(result).toEqual({
|
|
1124
|
+
versionNumber: 1,
|
|
1125
|
+
createdAt: new Date('2024-01-01T00:00:00.000Z')
|
|
1126
|
+
})
|
|
1127
|
+
})
|
|
1128
|
+
})
|
|
696
1129
|
})
|