Skip to content

Commit 4d33838

Browse files
Add min, max and length contraints to the GeospatialField (#399)
* Add min, max and length contraints to the GeospatialField * Bump forms-model for updated geospatial types
1 parent 4dd2cdb commit 4d33838

7 files changed

Lines changed: 406 additions & 37 deletions

File tree

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
},
8888
"license": "SEE LICENSE IN LICENSE",
8989
"dependencies": {
90-
"@defra/forms-model": "^3.0.663",
90+
"@defra/forms-model": "^3.0.667",
9191
"@defra/hapi-tracing": "^1.29.0",
9292
"@defra/interactive-map": "^0.0.22-alpha",
9393
"@elastic/ecs-pino-format": "^1.5.0",

src/server/plugins/engine/components/GeospatialField.test.ts

Lines changed: 302 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ describe('GeospatialField', () => {
261261
value: getFormData([]),
262262
errors: [
263263
expect.objectContaining({
264-
text: 'Example geospatial field must contain at least 1 items'
264+
text: 'Define at least 1 features'
265265
})
266266
]
267267
}
@@ -291,6 +291,171 @@ describe('GeospatialField', () => {
291291
}
292292
]
293293
},
294+
{
295+
description: 'Required with min constraints',
296+
component: {
297+
title: 'Example geospatial field',
298+
name: 'myComponent',
299+
type: ComponentType.GeospatialField,
300+
options: {
301+
required: true
302+
},
303+
schema: {
304+
min: 2
305+
}
306+
} satisfies GeospatialFieldComponent,
307+
assertions: [
308+
{
309+
input: getFormData([]),
310+
output: {
311+
value: getFormData([]),
312+
errors: [
313+
expect.objectContaining({
314+
text: 'Define at least 2 features'
315+
})
316+
]
317+
}
318+
},
319+
{
320+
input: getFormData(),
321+
output: {
322+
value: getFormData(),
323+
errors: [
324+
expect.objectContaining({
325+
text: 'Select example geospatial field'
326+
})
327+
]
328+
}
329+
},
330+
{
331+
input: getFormData(validSingleState),
332+
output: {
333+
value: getFormData(validSingleState),
334+
errors: [
335+
expect.objectContaining({
336+
text: 'Define at least 2 features'
337+
})
338+
]
339+
}
340+
},
341+
{
342+
input: getFormData(validState),
343+
output: {
344+
value: getFormData(validState)
345+
}
346+
}
347+
]
348+
},
349+
{
350+
description: 'Required with max constraints',
351+
component: {
352+
title: 'Example geospatial field',
353+
name: 'myComponent',
354+
type: ComponentType.GeospatialField,
355+
options: {
356+
required: true
357+
},
358+
schema: {
359+
max: 1
360+
}
361+
} satisfies GeospatialFieldComponent,
362+
assertions: [
363+
{
364+
input: getFormData([]),
365+
output: {
366+
value: getFormData([]),
367+
errors: [
368+
expect.objectContaining({
369+
text: 'Define at least 1 features'
370+
})
371+
]
372+
}
373+
},
374+
{
375+
input: getFormData(),
376+
output: {
377+
value: getFormData(),
378+
errors: [
379+
expect.objectContaining({
380+
text: 'Select example geospatial field'
381+
})
382+
]
383+
}
384+
},
385+
{
386+
input: getFormData(validSingleState),
387+
output: {
388+
value: getFormData(validSingleState)
389+
}
390+
},
391+
{
392+
input: getFormData(validState),
393+
output: {
394+
value: getFormData(validState),
395+
errors: [
396+
expect.objectContaining({
397+
text: 'Only 1 features can be defined'
398+
})
399+
]
400+
}
401+
}
402+
]
403+
},
404+
{
405+
description: 'Required with exact length constraints',
406+
component: {
407+
title: 'Example geospatial field',
408+
name: 'myComponent',
409+
type: ComponentType.GeospatialField,
410+
options: {
411+
required: true
412+
},
413+
schema: {
414+
length: 1
415+
}
416+
} satisfies GeospatialFieldComponent,
417+
assertions: [
418+
{
419+
input: getFormData([]),
420+
output: {
421+
value: getFormData([]),
422+
errors: [
423+
expect.objectContaining({
424+
text: 'Define exactly 1 features'
425+
})
426+
]
427+
}
428+
},
429+
{
430+
input: getFormData(),
431+
output: {
432+
value: getFormData(),
433+
errors: [
434+
expect.objectContaining({
435+
text: 'Select example geospatial field'
436+
})
437+
]
438+
}
439+
},
440+
{
441+
input: getFormData(validSingleState),
442+
output: {
443+
value: getFormData(validSingleState)
444+
}
445+
},
446+
{
447+
input: getFormData(validState),
448+
output: {
449+
value: getFormData(validState),
450+
errors: [
451+
expect.objectContaining({
452+
text: 'Define exactly 1 features'
453+
})
454+
]
455+
}
456+
}
457+
]
458+
},
294459
{
295460
description: 'Optional',
296461
component: {
@@ -307,14 +472,148 @@ describe('GeospatialField', () => {
307472
output: {
308473
value: getFormData([])
309474
}
475+
}
476+
]
477+
},
478+
{
479+
description: 'Optional with min constraints',
480+
component: {
481+
title: 'Example geospatial field',
482+
name: 'myComponent',
483+
type: ComponentType.GeospatialField,
484+
options: {
485+
required: false
486+
},
487+
schema: {
488+
min: 2
489+
}
490+
} satisfies GeospatialFieldComponent,
491+
assertions: [
492+
{
493+
input: getFormData([]),
494+
output: {
495+
value: getFormData([]),
496+
errors: [
497+
expect.objectContaining({
498+
text: 'Define at least 2 features'
499+
})
500+
]
501+
}
310502
},
311503
{
312504
input: getFormData(),
313505
output: {
314-
value: getFormData(),
506+
value: getFormData()
507+
}
508+
},
509+
{
510+
input: getFormData(validSingleState),
511+
output: {
512+
value: getFormData(validSingleState),
315513
errors: [
316514
expect.objectContaining({
317-
text: 'Select example geospatial field'
515+
text: 'Define at least 2 features'
516+
})
517+
]
518+
}
519+
},
520+
{
521+
input: getFormData(validState),
522+
output: {
523+
value: getFormData(validState)
524+
}
525+
}
526+
]
527+
},
528+
{
529+
description: 'Optional with max constraints',
530+
component: {
531+
title: 'Example geospatial field',
532+
name: 'myComponent',
533+
type: ComponentType.GeospatialField,
534+
options: {
535+
required: false
536+
},
537+
schema: {
538+
max: 1
539+
}
540+
} satisfies GeospatialFieldComponent,
541+
assertions: [
542+
{
543+
input: getFormData([]),
544+
output: {
545+
value: getFormData([])
546+
}
547+
},
548+
{
549+
input: getFormData(),
550+
output: {
551+
value: getFormData()
552+
}
553+
},
554+
{
555+
input: getFormData(validSingleState),
556+
output: {
557+
value: getFormData(validSingleState)
558+
}
559+
},
560+
{
561+
input: getFormData(validState),
562+
output: {
563+
value: getFormData(validState),
564+
errors: [
565+
expect.objectContaining({
566+
text: 'Only 1 features can be defined'
567+
})
568+
]
569+
}
570+
}
571+
]
572+
},
573+
{
574+
description: 'Optional with exact length constraints',
575+
component: {
576+
title: 'Example geospatial field',
577+
name: 'myComponent',
578+
type: ComponentType.GeospatialField,
579+
options: {
580+
required: false
581+
},
582+
schema: {
583+
length: 1
584+
}
585+
} satisfies GeospatialFieldComponent,
586+
assertions: [
587+
{
588+
input: getFormData([]),
589+
output: {
590+
value: getFormData([]),
591+
errors: [
592+
expect.objectContaining({
593+
text: 'Define exactly 1 features'
594+
})
595+
]
596+
}
597+
},
598+
{
599+
input: getFormData(),
600+
output: {
601+
value: getFormData()
602+
}
603+
},
604+
{
605+
input: getFormData(validSingleState),
606+
output: {
607+
value: getFormData(validSingleState)
608+
}
609+
},
610+
{
611+
input: getFormData(validState),
612+
output: {
613+
value: getFormData(validState),
614+
errors: [
615+
expect.objectContaining({
616+
text: 'Define exactly 1 features'
318617
})
319618
]
320619
}

src/server/plugins/engine/components/GeospatialField.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,21 @@ export class GeospatialField extends FormComponent {
3131

3232
const { options } = def
3333

34-
let formSchema = getGeospatialSchema(options.countries?.at(0))
34+
const formSchema = getGeospatialSchema(def)
3535
.label(this.label)
36-
.required()
36+
.messages({
37+
'array.min': messageTemplate.featuresMin as string,
38+
'array.max': messageTemplate.featuresMax as string,
39+
'array.length': messageTemplate.featuresLength as string
40+
})
3741

38-
formSchema = formSchema.max(50)
42+
this.formSchema = formSchema
43+
this.stateSchema = formSchema.default(null)
3944

40-
if (options.required !== false) {
41-
formSchema = formSchema.min(1)
45+
if (options.required === false) {
46+
this.stateSchema = this.stateSchema.allow(null)
4247
}
4348

44-
this.formSchema = formSchema
45-
this.stateSchema = formSchema.default(null)
4649
this.options = options
4750
}
4851

0 commit comments

Comments
 (0)