@defra/forms-engine-plugin 4.0.7 → 4.0.8
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/forms/components.json +7 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +12 -1
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentCollection.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +81 -0
- package/.server/server/plugins/engine/components/DeclarationField.js +123 -0
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +3 -0
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +1 -0
- package/.server/server/plugins/engine/components/index.js +1 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/validationOptions.js +1 -0
- package/.server/server/plugins/engine/pageControllers/validationOptions.js.map +1 -1
- package/.server/server/plugins/engine/views/components/declarationfield.html +14 -0
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/nunjucks/filters/index.d.ts +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js +1 -0
- package/.server/server/plugins/nunjucks/filters/index.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/merge.d.ts +7 -0
- package/.server/server/plugins/nunjucks/filters/merge.js +16 -0
- package/.server/server/plugins/nunjucks/filters/merge.js.map +1 -0
- package/.server/server/plugins/nunjucks/filters/merge.test.js +19 -0
- package/.server/server/plugins/nunjucks/filters/merge.test.js.map +1 -0
- package/package.json +2 -2
- package/src/server/forms/components.json +7 -0
- package/src/server/forms/page-events.yaml +1 -1
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +12 -1
- package/src/server/index.test.ts +1 -0
- package/src/server/plugins/engine/components/ComponentBase.ts +1 -0
- package/src/server/plugins/engine/components/ComponentCollection.ts +1 -0
- package/src/server/plugins/engine/components/DeclarationField.test.ts +426 -0
- package/src/server/plugins/engine/components/DeclarationField.ts +167 -0
- package/src/server/plugins/engine/components/helpers/components.ts +5 -0
- package/src/server/plugins/engine/components/index.ts +1 -0
- package/src/server/plugins/engine/models/SummaryViewModel.test.ts +76 -3
- package/src/server/plugins/engine/models/SummaryViewModel.ts +5 -1
- package/src/server/plugins/engine/pageControllers/validationOptions.ts +4 -0
- package/src/server/plugins/engine/views/components/declarationfield.html +14 -0
- package/src/server/plugins/nunjucks/filters/index.js +1 -0
- package/src/server/plugins/nunjucks/filters/merge.js +16 -0
- package/src/server/plugins/nunjucks/filters/merge.test.js +15 -0
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* @this {NunjucksContext}
|
|
4
4
|
* @param {string} name - The name of the component
|
|
5
5
|
*/
|
|
6
|
-
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
6
|
+
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/DeclarationField.js").DeclarationField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
7
7
|
import type { NunjucksContext } from '~/src/server/plugins/nunjucks/types.js';
|
|
@@ -5,3 +5,4 @@ export { answer } from "~/src/server/plugins/nunjucks/filters/answer.js";
|
|
|
5
5
|
export { href } from "~/src/server/plugins/nunjucks/filters/href.js";
|
|
6
6
|
export { field } from "~/src/server/plugins/nunjucks/filters/field.js";
|
|
7
7
|
export { page } from "~/src/server/plugins/nunjucks/filters/page.js";
|
|
8
|
+
export { merge } from "~/src/server/plugins/nunjucks/filters/merge.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["highlight","inspect","evaluate","answer","href","field","page"],"sources":["../../../../../src/server/plugins/nunjucks/filters/index.js"],"sourcesContent":["export { highlight } from '~/src/server/plugins/nunjucks/filters/highlight.js'\nexport { inspect } from '~/src/server/plugins/nunjucks/filters/inspect.js'\nexport { evaluate } from '~/src/server/plugins/nunjucks/filters/evaluate.js'\nexport { answer } from '~/src/server/plugins/nunjucks/filters/answer.js'\nexport { href } from '~/src/server/plugins/nunjucks/filters/href.js'\nexport { field } from '~/src/server/plugins/nunjucks/filters/field.js'\nexport { page } from '~/src/server/plugins/nunjucks/filters/page.js'\n"],"mappings":"AAAA,SAASA,SAAS;AAClB,SAASC,OAAO;AAChB,SAASC,QAAQ;AACjB,SAASC,MAAM;AACf,SAASC,IAAI;AACb,SAASC,KAAK;AACd,SAASC,IAAI","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["highlight","inspect","evaluate","answer","href","field","page","merge"],"sources":["../../../../../src/server/plugins/nunjucks/filters/index.js"],"sourcesContent":["export { highlight } from '~/src/server/plugins/nunjucks/filters/highlight.js'\nexport { inspect } from '~/src/server/plugins/nunjucks/filters/inspect.js'\nexport { evaluate } from '~/src/server/plugins/nunjucks/filters/evaluate.js'\nexport { answer } from '~/src/server/plugins/nunjucks/filters/answer.js'\nexport { href } from '~/src/server/plugins/nunjucks/filters/href.js'\nexport { field } from '~/src/server/plugins/nunjucks/filters/field.js'\nexport { page } from '~/src/server/plugins/nunjucks/filters/page.js'\nexport { merge } from '~/src/server/plugins/nunjucks/filters/merge.js'\n"],"mappings":"AAAA,SAASA,SAAS;AAClB,SAASC,OAAO;AAChB,SAASC,QAAQ;AACjB,SAASC,MAAM;AACf,SAASC,IAAI;AACb,SAASC,KAAK;AACd,SAASC,IAAI;AACb,SAASC,KAAK","ignoreList":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nunjucks filter to get the page for a given path
|
|
3
|
+
* @param {Record<string, any>} targetDictionary - Object to extend
|
|
4
|
+
* @param {Record<string, any> | string} sourceDictionary - Object to merge into target
|
|
5
|
+
* @returns {Record<string, any>}
|
|
6
|
+
*/
|
|
7
|
+
export function merge(targetDictionary: Record<string, any>, sourceDictionary: Record<string, any> | string): Record<string, any>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nunjucks filter to get the page for a given path
|
|
3
|
+
* @param {Record<string, any>} targetDictionary - Object to extend
|
|
4
|
+
* @param {Record<string, any> | string} sourceDictionary - Object to merge into target
|
|
5
|
+
* @returns {Record<string, any>}
|
|
6
|
+
*/
|
|
7
|
+
export function merge(targetDictionary, sourceDictionary) {
|
|
8
|
+
if (typeof sourceDictionary !== 'object') {
|
|
9
|
+
return targetDictionary;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
...targetDictionary,
|
|
13
|
+
...sourceDictionary
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","names":["merge","targetDictionary","sourceDictionary"],"sources":["../../../../../src/server/plugins/nunjucks/filters/merge.js"],"sourcesContent":["/**\n * Nunjucks filter to get the page for a given path\n * @param {Record<string, any>} targetDictionary - Object to extend\n * @param {Record<string, any> | string} sourceDictionary - Object to merge into target\n * @returns {Record<string, any>}\n */\nexport function merge(targetDictionary, sourceDictionary) {\n if (typeof sourceDictionary !== 'object') {\n return targetDictionary\n }\n\n return {\n ...targetDictionary,\n ...sourceDictionary\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,KAAKA,CAACC,gBAAgB,EAAEC,gBAAgB,EAAE;EACxD,IAAI,OAAOA,gBAAgB,KAAK,QAAQ,EAAE;IACxC,OAAOD,gBAAgB;EACzB;EAEA,OAAO;IACL,GAAGA,gBAAgB;IACnB,GAAGC;EACL,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { merge } from "./merge.js";
|
|
2
|
+
describe('merge', () => {
|
|
3
|
+
const propertyToMerge = {
|
|
4
|
+
lorem: 'ipsum'
|
|
5
|
+
};
|
|
6
|
+
it('should return the target if source is not an object', () => {
|
|
7
|
+
expect(merge(propertyToMerge, 'dolar')).toBe(propertyToMerge);
|
|
8
|
+
});
|
|
9
|
+
it('should merge the properties if they are valid', () => {
|
|
10
|
+
expect(merge({
|
|
11
|
+
lorem: 'dolar',
|
|
12
|
+
dolar: 'sit'
|
|
13
|
+
}, propertyToMerge)).toEqual({
|
|
14
|
+
lorem: 'ipsum',
|
|
15
|
+
dolar: 'sit'
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=merge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.test.js","names":["merge","describe","propertyToMerge","lorem","it","expect","toBe","dolar","toEqual"],"sources":["../../../../../src/server/plugins/nunjucks/filters/merge.test.js"],"sourcesContent":["import { merge } from '~/src/server/plugins/nunjucks/filters/merge.js'\n\ndescribe('merge', () => {\n const propertyToMerge = { lorem: 'ipsum' }\n it('should return the target if source is not an object', () => {\n expect(merge(propertyToMerge, 'dolar')).toBe(propertyToMerge)\n })\n\n it('should merge the properties if they are valid', () => {\n expect(merge({ lorem: 'dolar', dolar: 'sit' }, propertyToMerge)).toEqual({\n lorem: 'ipsum',\n dolar: 'sit'\n })\n })\n})\n"],"mappings":"AAAA,SAASA,KAAK;AAEdC,QAAQ,CAAC,OAAO,EAAE,MAAM;EACtB,MAAMC,eAAe,GAAG;IAAEC,KAAK,EAAE;EAAQ,CAAC;EAC1CC,EAAE,CAAC,qDAAqD,EAAE,MAAM;IAC9DC,MAAM,CAACL,KAAK,CAACE,eAAe,EAAE,OAAO,CAAC,CAAC,CAACI,IAAI,CAACJ,eAAe,CAAC;EAC/D,CAAC,CAAC;EAEFE,EAAE,CAAC,+CAA+C,EAAE,MAAM;IACxDC,MAAM,CAACL,KAAK,CAAC;MAAEG,KAAK,EAAE,OAAO;MAAEI,KAAK,EAAE;IAAM,CAAC,EAAEL,eAAe,CAAC,CAAC,CAACM,OAAO,CAAC;MACvEL,KAAK,EAAE,OAAO;MACdI,KAAK,EAAE;IACT,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra/forms-engine-plugin",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.8",
|
|
4
4
|
"description": "Defra forms engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"license": "SEE LICENSE IN LICENSE",
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@defra/forms-model": "^3.0.
|
|
73
|
+
"@defra/forms-model": "^3.0.574",
|
|
74
74
|
"@defra/hapi-tracing": "^1.26.0",
|
|
75
75
|
"@elastic/ecs-pino-format": "^1.5.0",
|
|
76
76
|
"@hapi/boom": "^10.0.1",
|
|
@@ -120,6 +120,13 @@
|
|
|
120
120
|
"content": "### This is a H3 in markdown\n\n[An internal link](http://localhost:3009/fictional-page)\n\n[An external link](https://defra.gov.uk/fictional-page)",
|
|
121
121
|
"options": {},
|
|
122
122
|
"schema": {}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"type": "DeclarationField",
|
|
126
|
+
"name": "declaration",
|
|
127
|
+
"title": "Declaration",
|
|
128
|
+
"content": "By submitting this form, I agree to:\n\n- Provide accurate and complete information\n- Comply with all applicable regulations\n- Accept responsibility for any false statements",
|
|
129
|
+
"hint": "Please read and confirm the following terms"
|
|
123
130
|
}
|
|
124
131
|
]
|
|
125
132
|
},
|
|
@@ -219,7 +219,7 @@ pages:
|
|
|
219
219
|
controller: FileUploadPageController
|
|
220
220
|
section: Regnsa
|
|
221
221
|
next:
|
|
222
|
-
- path: '/
|
|
222
|
+
- path: '/declaration'
|
|
223
223
|
components:
|
|
224
224
|
- name: dLzALM
|
|
225
225
|
title: Documents
|
|
@@ -230,6 +230,17 @@ pages:
|
|
|
230
230
|
schema:
|
|
231
231
|
min: 1
|
|
232
232
|
max: 3
|
|
233
|
+
- title: Declaration
|
|
234
|
+
path: '/declaration'
|
|
235
|
+
section: section
|
|
236
|
+
components:
|
|
237
|
+
- name: diLmal
|
|
238
|
+
title: Declaration
|
|
239
|
+
type: DeclarationField
|
|
240
|
+
content: 'Fill in this field'
|
|
241
|
+
options: {}
|
|
242
|
+
next:
|
|
243
|
+
- path: '/summary'
|
|
233
244
|
conditions:
|
|
234
245
|
- displayName: Address is different
|
|
235
246
|
name: IrVmYz
|
package/src/server/index.test.ts
CHANGED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentType,
|
|
3
|
+
type DeclarationFieldComponent
|
|
4
|
+
} from '@defra/forms-model'
|
|
5
|
+
|
|
6
|
+
import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
|
|
7
|
+
import { DeclarationField } from '~/src/server/plugins/engine/components/DeclarationField.js'
|
|
8
|
+
import {
|
|
9
|
+
getAnswer,
|
|
10
|
+
type Field
|
|
11
|
+
} from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
12
|
+
import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
|
|
13
|
+
import definition from '~/test/form/definitions/blank.js'
|
|
14
|
+
import { getFormData, getFormState } from '~/test/helpers/component-helpers.js'
|
|
15
|
+
|
|
16
|
+
describe('DeclarationField', () => {
|
|
17
|
+
let model: FormModel
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
model = new FormModel(definition, {
|
|
21
|
+
basePath: 'test'
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('Defaults', () => {
|
|
26
|
+
let def: DeclarationFieldComponent
|
|
27
|
+
let collection: ComponentCollection
|
|
28
|
+
let field: Field
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
def = {
|
|
32
|
+
title: 'Example Declaration Component',
|
|
33
|
+
name: 'myComponent',
|
|
34
|
+
content: 'Lorem ipsum dolar sit amet',
|
|
35
|
+
shortDescription: 'Terms and conditions',
|
|
36
|
+
type: ComponentType.DeclarationField,
|
|
37
|
+
options: {}
|
|
38
|
+
} satisfies DeclarationFieldComponent
|
|
39
|
+
|
|
40
|
+
collection = new ComponentCollection([def], { model })
|
|
41
|
+
field = collection.fields[0]
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('Schema', () => {
|
|
45
|
+
it('uses component title as label as default', () => {
|
|
46
|
+
const { formSchema } = collection
|
|
47
|
+
const { keys } = formSchema.describe()
|
|
48
|
+
|
|
49
|
+
expect(keys).toHaveProperty(
|
|
50
|
+
'myComponent',
|
|
51
|
+
expect.objectContaining({
|
|
52
|
+
flags: expect.objectContaining({
|
|
53
|
+
label: 'Terms and conditions'
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('uses component name as keys', () => {
|
|
60
|
+
const { formSchema } = collection
|
|
61
|
+
const { keys } = formSchema.describe()
|
|
62
|
+
|
|
63
|
+
expect(field.keys).toEqual(['myComponent'])
|
|
64
|
+
expect(field.collection).toBeUndefined()
|
|
65
|
+
|
|
66
|
+
for (const key of field.keys) {
|
|
67
|
+
expect(keys).toHaveProperty(key)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('is required by default', () => {
|
|
72
|
+
const { formSchema } = collection
|
|
73
|
+
const { keys } = formSchema.describe()
|
|
74
|
+
|
|
75
|
+
expect(keys).toHaveProperty(
|
|
76
|
+
'myComponent',
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
items: expect.arrayContaining([
|
|
79
|
+
expect.objectContaining({
|
|
80
|
+
allow: ['true'],
|
|
81
|
+
flags: expect.objectContaining({
|
|
82
|
+
presence: 'required'
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
])
|
|
86
|
+
})
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('may have unchecked value in addition to true', () => {
|
|
91
|
+
const { formSchema } = collection
|
|
92
|
+
const { keys } = formSchema.describe()
|
|
93
|
+
|
|
94
|
+
expect(keys).toHaveProperty(
|
|
95
|
+
'myComponent',
|
|
96
|
+
expect.objectContaining({
|
|
97
|
+
items: expect.arrayContaining([
|
|
98
|
+
expect.objectContaining({
|
|
99
|
+
allow: ['unchecked'],
|
|
100
|
+
flags: expect.objectContaining({
|
|
101
|
+
result: 'strip'
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
])
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
expect(keys).toHaveProperty(
|
|
109
|
+
'myComponent',
|
|
110
|
+
expect.objectContaining({
|
|
111
|
+
items: expect.arrayContaining([
|
|
112
|
+
expect.objectContaining({
|
|
113
|
+
allow: ['unchecked']
|
|
114
|
+
})
|
|
115
|
+
])
|
|
116
|
+
})
|
|
117
|
+
)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('is optional when configured', () => {
|
|
121
|
+
const collectionOptional = new ComponentCollection(
|
|
122
|
+
[{ ...def, options: { required: false } }],
|
|
123
|
+
{ model }
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const { formSchema } = collectionOptional
|
|
127
|
+
const { keys } = formSchema.describe()
|
|
128
|
+
|
|
129
|
+
expect(keys).toHaveProperty(
|
|
130
|
+
'myComponent',
|
|
131
|
+
expect.objectContaining({
|
|
132
|
+
items: expect.arrayContaining([
|
|
133
|
+
expect.objectContaining({
|
|
134
|
+
allow: ['true'],
|
|
135
|
+
flags: expect.not.objectContaining({
|
|
136
|
+
presence: 'required'
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
])
|
|
140
|
+
})
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
const result = collectionOptional.validate(getFormData(['unchecked']))
|
|
144
|
+
expect(result.errors).toBeUndefined()
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('accepts valid values', () => {
|
|
148
|
+
const result1 = collection.validate(getFormData(['unchecked', 'true']))
|
|
149
|
+
|
|
150
|
+
expect(result1.errors).toBeUndefined()
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('adds errors for empty value', () => {
|
|
154
|
+
const result = collection.validate(getFormData(['unchecked']))
|
|
155
|
+
|
|
156
|
+
expect(result.errors).toEqual([
|
|
157
|
+
expect.objectContaining({
|
|
158
|
+
text: 'You must confirm you understand and agree with the terms and conditions to continue'
|
|
159
|
+
})
|
|
160
|
+
])
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('adds errors for invalid values', () => {
|
|
164
|
+
const result1 = collection.validate(getFormData(['invalid']))
|
|
165
|
+
const result2 = collection.validate(
|
|
166
|
+
// @ts-expect-error - Allow invalid param for test
|
|
167
|
+
getFormData({ unknown: 'invalid' })
|
|
168
|
+
)
|
|
169
|
+
// @ts-expect-error - Allow invalid param for test
|
|
170
|
+
const result3 = collection.validate('false')
|
|
171
|
+
|
|
172
|
+
expect(result1.errors).toBeTruthy()
|
|
173
|
+
expect(result2.errors).toBeTruthy()
|
|
174
|
+
expect(result3.errors).toBeTruthy()
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('State', () => {
|
|
179
|
+
it('returns text from state', () => {
|
|
180
|
+
const state1 = getFormState(true)
|
|
181
|
+
const state2 = getFormState()
|
|
182
|
+
// context - boolean
|
|
183
|
+
// state - boolean
|
|
184
|
+
// string - I confirm that I understand and accept this declaration
|
|
185
|
+
const answer1 = getAnswer(field, state1)
|
|
186
|
+
const answer2 = getAnswer(field, state2)
|
|
187
|
+
|
|
188
|
+
expect(answer1).toBe('I understand and agree')
|
|
189
|
+
expect(answer2).toBe('')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('returns payload from state', () => {
|
|
193
|
+
const state1 = getFormState(true)
|
|
194
|
+
const state2 = getFormState(null)
|
|
195
|
+
|
|
196
|
+
const payload1 = field.getFormDataFromState(state1)
|
|
197
|
+
const payload2 = field.getFormDataFromState(state2)
|
|
198
|
+
|
|
199
|
+
expect(payload1).toEqual(getFormData('true'))
|
|
200
|
+
expect(payload2).toEqual(getFormData())
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('returns value from state', () => {
|
|
204
|
+
const state1 = getFormState(true)
|
|
205
|
+
const state2 = getFormState(null)
|
|
206
|
+
|
|
207
|
+
const value1 = field.getFormValueFromState(state1)
|
|
208
|
+
const value2 = field.getFormValueFromState(state2)
|
|
209
|
+
|
|
210
|
+
expect(value1).toBe('true')
|
|
211
|
+
expect(value2).toBeUndefined()
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('returns context for conditions and form submission', () => {
|
|
215
|
+
const state1 = getFormState(true)
|
|
216
|
+
const state2 = getFormState(null)
|
|
217
|
+
|
|
218
|
+
const value1 = field.getContextValueFromState(state1)
|
|
219
|
+
const value2 = field.getContextValueFromState(state2)
|
|
220
|
+
|
|
221
|
+
expect(value1).toBe(true)
|
|
222
|
+
expect(value2).toBe(false)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('returns state from payload', () => {
|
|
226
|
+
const payload1 = getFormData(['true'])
|
|
227
|
+
const payload2 = getFormData([])
|
|
228
|
+
const payload3 = getFormData(['unchecked'])
|
|
229
|
+
|
|
230
|
+
const value1 = field.getStateFromValidForm(payload1)
|
|
231
|
+
const value2 = field.getStateFromValidForm(payload2)
|
|
232
|
+
const value3 = field.getStateFromValidForm(payload3)
|
|
233
|
+
|
|
234
|
+
expect(value1).toEqual(getFormState(true))
|
|
235
|
+
expect(value2).toEqual(getFormState(false))
|
|
236
|
+
expect(value3).toEqual(getFormState(false))
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
describe('View model', () => {
|
|
241
|
+
it('sets Nunjucks component defaults', () => {
|
|
242
|
+
const viewModel = field.getViewModel(getFormData([]))
|
|
243
|
+
|
|
244
|
+
expect(viewModel).toEqual(
|
|
245
|
+
expect.objectContaining({
|
|
246
|
+
label: { text: def.title },
|
|
247
|
+
name: 'myComponent',
|
|
248
|
+
attributes: {},
|
|
249
|
+
values: [],
|
|
250
|
+
content: 'Lorem ipsum dolar sit amet',
|
|
251
|
+
id: 'myComponent',
|
|
252
|
+
fieldset: {
|
|
253
|
+
legend: {
|
|
254
|
+
text: 'Example Declaration Component'
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
items: [
|
|
258
|
+
{
|
|
259
|
+
value: 'true',
|
|
260
|
+
text: 'I understand and agree'
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
})
|
|
264
|
+
)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('sets Nunjucks component value when posted', () => {
|
|
268
|
+
def = {
|
|
269
|
+
...def,
|
|
270
|
+
hint: 'Please read and confirm the following'
|
|
271
|
+
} satisfies DeclarationFieldComponent
|
|
272
|
+
|
|
273
|
+
collection = new ComponentCollection([def], { model })
|
|
274
|
+
field = collection.fields[0]
|
|
275
|
+
const viewModel = field.getViewModel(getFormData(['true']))
|
|
276
|
+
|
|
277
|
+
expect(viewModel).toEqual(
|
|
278
|
+
expect.objectContaining({
|
|
279
|
+
values: ['true'],
|
|
280
|
+
hint: {
|
|
281
|
+
text: 'Please read and confirm the following'
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('sets custom message when in def', () => {
|
|
288
|
+
def = {
|
|
289
|
+
...def,
|
|
290
|
+
title: 'Declaration',
|
|
291
|
+
content:
|
|
292
|
+
'Declaration:\n' +
|
|
293
|
+
'By submitting this form, I consent to the collection and processing of my personal data for the purposes described.\n' +
|
|
294
|
+
'I understand that my data may be shared with authorised third parties where required by law',
|
|
295
|
+
options: {
|
|
296
|
+
declarationConfirmationLabel:
|
|
297
|
+
'I consent to the processing of my personal data'
|
|
298
|
+
}
|
|
299
|
+
} satisfies DeclarationFieldComponent
|
|
300
|
+
|
|
301
|
+
collection = new ComponentCollection([def], { model })
|
|
302
|
+
field = collection.fields[0]
|
|
303
|
+
|
|
304
|
+
const viewModel = field.getViewModel(getFormData(['unchecked', 'true']))
|
|
305
|
+
|
|
306
|
+
expect(viewModel).toEqual(
|
|
307
|
+
expect.objectContaining({
|
|
308
|
+
items: [
|
|
309
|
+
{
|
|
310
|
+
value: 'true',
|
|
311
|
+
text: 'I consent to the processing of my personal data'
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
})
|
|
315
|
+
)
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
describe('AllPossibleErrors', () => {
|
|
320
|
+
it('should return errors', () => {
|
|
321
|
+
const errors = field.getAllPossibleErrors()
|
|
322
|
+
expect(errors.baseErrors).not.toBeEmpty()
|
|
323
|
+
expect(errors.advancedSettingsErrors).toBeEmpty()
|
|
324
|
+
})
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
describe('getFormValue', () => {
|
|
328
|
+
test('should return correct value', () => {
|
|
329
|
+
expect(field.getFormValue(undefined)).toBeUndefined()
|
|
330
|
+
expect(field.getFormValue([true])).toEqual([true])
|
|
331
|
+
expect(field.getFormValue([])).toEqual([])
|
|
332
|
+
expect(field.getFormValue({})).toBeUndefined()
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
describe('Validation', () => {
|
|
338
|
+
describe.each([
|
|
339
|
+
{
|
|
340
|
+
description: 'Default',
|
|
341
|
+
component: {
|
|
342
|
+
title: 'Terms and conditions',
|
|
343
|
+
shortDescription: 'The terms and conditions',
|
|
344
|
+
content: 'Lorem ipsum dolar sit amet',
|
|
345
|
+
name: 'myComponent',
|
|
346
|
+
type: ComponentType.DeclarationField,
|
|
347
|
+
options: {}
|
|
348
|
+
} satisfies DeclarationFieldComponent,
|
|
349
|
+
assertions: [
|
|
350
|
+
{
|
|
351
|
+
input: getFormData(['unchecked', 'true']),
|
|
352
|
+
output: {
|
|
353
|
+
value: {
|
|
354
|
+
myComponent: ['true']
|
|
355
|
+
},
|
|
356
|
+
errors: undefined
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
description: 'Use short description if it exists',
|
|
363
|
+
component: {
|
|
364
|
+
title: 'Terms and conditions',
|
|
365
|
+
shortDescription: 'Terms and conditions',
|
|
366
|
+
content: 'Lorem ipsum dolar sit amet',
|
|
367
|
+
name: 'myComponent',
|
|
368
|
+
type: ComponentType.DeclarationField,
|
|
369
|
+
options: {}
|
|
370
|
+
} satisfies DeclarationFieldComponent,
|
|
371
|
+
assertions: [
|
|
372
|
+
{
|
|
373
|
+
input: getFormData(['unchecked']),
|
|
374
|
+
output: {
|
|
375
|
+
value: { myComponent: [] },
|
|
376
|
+
errors: [
|
|
377
|
+
expect.objectContaining({
|
|
378
|
+
text: 'You must confirm you understand and agree with the terms and conditions to continue'
|
|
379
|
+
})
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
description: 'Optional field',
|
|
387
|
+
component: {
|
|
388
|
+
title: 'Example text field',
|
|
389
|
+
name: 'myComponent',
|
|
390
|
+
content: 'Lorem ipsum dolar sit amet',
|
|
391
|
+
type: ComponentType.DeclarationField,
|
|
392
|
+
options: {
|
|
393
|
+
required: false
|
|
394
|
+
}
|
|
395
|
+
} satisfies DeclarationFieldComponent,
|
|
396
|
+
assertions: [
|
|
397
|
+
{
|
|
398
|
+
input: getFormData(['unchecked']),
|
|
399
|
+
output: { value: { myComponent: [] } }
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
])('$description', ({ component: def, assertions }) => {
|
|
404
|
+
let collection: ComponentCollection
|
|
405
|
+
|
|
406
|
+
beforeEach(() => {
|
|
407
|
+
collection = new ComponentCollection([def], { model })
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
it.each([...assertions])(
|
|
411
|
+
'validates custom example',
|
|
412
|
+
({ input, output }) => {
|
|
413
|
+
const result = collection.validate(input)
|
|
414
|
+
expect(result).toEqual(output)
|
|
415
|
+
}
|
|
416
|
+
)
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
describe('isBool', () => {
|
|
421
|
+
test('should return correct boolean', () => {
|
|
422
|
+
expect(DeclarationField.isBool('string')).toBe(false)
|
|
423
|
+
expect(DeclarationField.isBool(true)).toBe(true)
|
|
424
|
+
})
|
|
425
|
+
})
|
|
426
|
+
})
|