@defra/forms-engine-plugin 4.0.10 → 4.0.12
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/register-as-a-unicorn-breeder.yaml +2 -2
- package/.server/server/plugins/engine/components/EastingNorthingField.js +4 -24
- package/.server/server/plugins/engine/components/EastingNorthingField.js.map +1 -1
- package/.server/server/plugins/engine/components/LatLongField.js +8 -31
- package/.server/server/plugins/engine/components/LatLongField.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +1 -3
- package/.server/server/plugins/engine/components/LocationFieldBase.js +1 -8
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +0 -2
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js +7 -18
- package/.server/server/plugins/engine/components/NationalGridFieldNumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/NumberField.d.ts +0 -18
- package/.server/server/plugins/engine/components/NumberField.js +2 -103
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/OsGridRefField.d.ts +0 -2
- package/.server/server/plugins/engine/components/OsGridRefField.js +4 -32
- package/.server/server/plugins/engine/components/OsGridRefField.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/pages.d.ts +1 -2
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js +1 -11
- package/.server/server/plugins/engine/pageControllers/helpers/pages.js.map +1 -1
- package/package.json +1 -1
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +2 -2
- package/src/server/plugins/engine/components/EastingNorthingField.test.ts +0 -14
- package/src/server/plugins/engine/components/EastingNorthingField.ts +4 -24
- package/src/server/plugins/engine/components/LatLongField.test.ts +4 -24
- package/src/server/plugins/engine/components/LatLongField.ts +8 -33
- package/src/server/plugins/engine/components/LocationFieldBase.ts +1 -15
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +22 -8
- package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +9 -20
- package/src/server/plugins/engine/components/NumberField.test.ts +12 -504
- package/src/server/plugins/engine/components/NumberField.ts +4 -133
- package/src/server/plugins/engine/components/OsGridRefField.test.ts +11 -33
- package/src/server/plugins/engine/components/OsGridRefField.ts +5 -38
- package/src/server/plugins/engine/pageControllers/helpers/helpers.test.ts +4 -24
- package/src/server/plugins/engine/pageControllers/helpers/pages.ts +0 -15
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { ComponentType, type NumberFieldComponent } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js'
|
|
4
|
-
import {
|
|
5
|
-
NumberField,
|
|
6
|
-
validateMinimumPrecision,
|
|
7
|
-
validateStringLength
|
|
8
|
-
} from '~/src/server/plugins/engine/components/NumberField.js'
|
|
4
|
+
import { NumberField } from '~/src/server/plugins/engine/components/NumberField.js'
|
|
9
5
|
import {
|
|
10
6
|
getAnswer,
|
|
11
7
|
type Field
|
|
@@ -23,94 +19,6 @@ describe('NumberField', () => {
|
|
|
23
19
|
})
|
|
24
20
|
})
|
|
25
21
|
|
|
26
|
-
describe('Helper Functions', () => {
|
|
27
|
-
describe('validateStringLength', () => {
|
|
28
|
-
it('returns valid when no constraints provided', () => {
|
|
29
|
-
expect(validateStringLength(123)).toEqual({ isValid: true })
|
|
30
|
-
expect(validateStringLength(123, undefined, undefined)).toEqual({
|
|
31
|
-
isValid: true
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('validates minimum length correctly', () => {
|
|
36
|
-
expect(validateStringLength(12, 3)).toEqual({
|
|
37
|
-
isValid: false,
|
|
38
|
-
error: 'minLength'
|
|
39
|
-
})
|
|
40
|
-
expect(validateStringLength(123, 3)).toEqual({ isValid: true })
|
|
41
|
-
expect(validateStringLength(1234, 3)).toEqual({ isValid: true })
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('validates maximum length correctly', () => {
|
|
45
|
-
expect(validateStringLength(123456, undefined, 5)).toEqual({
|
|
46
|
-
isValid: false,
|
|
47
|
-
error: 'maxLength'
|
|
48
|
-
})
|
|
49
|
-
expect(validateStringLength(12345, undefined, 5)).toEqual({
|
|
50
|
-
isValid: true
|
|
51
|
-
})
|
|
52
|
-
expect(validateStringLength(123, undefined, 5)).toEqual({
|
|
53
|
-
isValid: true
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('validates both min and max length', () => {
|
|
58
|
-
expect(validateStringLength(12, 3, 5)).toEqual({
|
|
59
|
-
isValid: false,
|
|
60
|
-
error: 'minLength'
|
|
61
|
-
})
|
|
62
|
-
expect(validateStringLength(123456, 3, 5)).toEqual({
|
|
63
|
-
isValid: false,
|
|
64
|
-
error: 'maxLength'
|
|
65
|
-
})
|
|
66
|
-
expect(validateStringLength(1234, 3, 5)).toEqual({ isValid: true })
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('handles decimal numbers correctly', () => {
|
|
70
|
-
// "52.1" = 4 characters
|
|
71
|
-
expect(validateStringLength(52.1, 3, 5)).toEqual({ isValid: true })
|
|
72
|
-
// "52.123456" = 9 characters
|
|
73
|
-
expect(validateStringLength(52.123456, undefined, 8)).toEqual({
|
|
74
|
-
isValid: false,
|
|
75
|
-
error: 'maxLength'
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('handles negative numbers correctly', () => {
|
|
80
|
-
// "-1.5" = 4 characters
|
|
81
|
-
expect(validateStringLength(-1.5, 3, 5)).toEqual({ isValid: true })
|
|
82
|
-
// "-9.1234567" = 10 characters
|
|
83
|
-
expect(validateStringLength(-9.1234567, undefined, 9)).toEqual({
|
|
84
|
-
isValid: false,
|
|
85
|
-
error: 'maxLength'
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
describe('validateMinimumPrecision', () => {
|
|
91
|
-
it('returns false for integers', () => {
|
|
92
|
-
expect(validateMinimumPrecision(52, 1)).toBe(false)
|
|
93
|
-
expect(validateMinimumPrecision(100, 2)).toBe(false)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('validates minimum precision correctly', () => {
|
|
97
|
-
expect(validateMinimumPrecision(52.1, 1)).toBe(true)
|
|
98
|
-
expect(validateMinimumPrecision(52.12, 2)).toBe(true)
|
|
99
|
-
expect(validateMinimumPrecision(52.123, 3)).toBe(true)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('returns false when precision is insufficient', () => {
|
|
103
|
-
expect(validateMinimumPrecision(52.1, 2)).toBe(false)
|
|
104
|
-
expect(validateMinimumPrecision(52.12, 3)).toBe(false)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('handles exact precision requirement', () => {
|
|
108
|
-
expect(validateMinimumPrecision(52.12345, 5)).toBe(true)
|
|
109
|
-
expect(validateMinimumPrecision(52.1234, 5)).toBe(false)
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
22
|
describe('Defaults', () => {
|
|
115
23
|
let def: NumberFieldComponent
|
|
116
24
|
let collection: ComponentCollection
|
|
@@ -596,184 +504,17 @@ describe('NumberField', () => {
|
|
|
596
504
|
]
|
|
597
505
|
},
|
|
598
506
|
{
|
|
599
|
-
description: 'Schema
|
|
600
|
-
component: createPrecisionTestComponent(1),
|
|
601
|
-
assertions: [
|
|
602
|
-
{
|
|
603
|
-
input: getFormData('52'),
|
|
604
|
-
output: {
|
|
605
|
-
value: getFormData(52),
|
|
606
|
-
errors: [
|
|
607
|
-
expect.objectContaining({
|
|
608
|
-
text: 'Example number field must have at least 1 decimal place'
|
|
609
|
-
})
|
|
610
|
-
]
|
|
611
|
-
}
|
|
612
|
-
},
|
|
613
|
-
{
|
|
614
|
-
input: getFormData('52.0'),
|
|
615
|
-
output: {
|
|
616
|
-
value: getFormData(52),
|
|
617
|
-
errors: [
|
|
618
|
-
expect.objectContaining({
|
|
619
|
-
text: 'Example number field must have at least 1 decimal place'
|
|
620
|
-
})
|
|
621
|
-
]
|
|
622
|
-
}
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
input: getFormData('52.1'),
|
|
626
|
-
output: { value: getFormData(52.1) }
|
|
627
|
-
},
|
|
628
|
-
{
|
|
629
|
-
input: getFormData('52.123456'),
|
|
630
|
-
output: { value: getFormData(52.123456) }
|
|
631
|
-
}
|
|
632
|
-
]
|
|
633
|
-
},
|
|
634
|
-
{
|
|
635
|
-
description: 'Schema minPrecision (minimum 2 decimal places)',
|
|
636
|
-
component: createPrecisionTestComponent(2),
|
|
637
|
-
assertions: [
|
|
638
|
-
{
|
|
639
|
-
input: getFormData('52.1'),
|
|
640
|
-
output: {
|
|
641
|
-
value: getFormData(52.1),
|
|
642
|
-
errors: [
|
|
643
|
-
expect.objectContaining({
|
|
644
|
-
text: 'Example number field must have at least 2 decimal places'
|
|
645
|
-
})
|
|
646
|
-
]
|
|
647
|
-
}
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
input: getFormData('52.12'),
|
|
651
|
-
output: { value: getFormData(52.12) }
|
|
652
|
-
},
|
|
653
|
-
{
|
|
654
|
-
input: getFormData('52.1234567'),
|
|
655
|
-
output: { value: getFormData(52.1234567) }
|
|
656
|
-
}
|
|
657
|
-
]
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
description: 'Schema minLength (minimum 3 characters)',
|
|
661
|
-
component: createLengthTestComponent(3, undefined),
|
|
662
|
-
assertions: [
|
|
663
|
-
{
|
|
664
|
-
input: getFormData('12'),
|
|
665
|
-
output: {
|
|
666
|
-
value: getFormData(12),
|
|
667
|
-
errors: [
|
|
668
|
-
expect.objectContaining({
|
|
669
|
-
text: 'Example number field must be at least 3 characters'
|
|
670
|
-
})
|
|
671
|
-
]
|
|
672
|
-
}
|
|
673
|
-
},
|
|
674
|
-
{
|
|
675
|
-
input: getFormData('123'),
|
|
676
|
-
output: { value: getFormData(123) }
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
input: getFormData('1234'),
|
|
680
|
-
output: { value: getFormData(1234) }
|
|
681
|
-
}
|
|
682
|
-
]
|
|
683
|
-
},
|
|
684
|
-
{
|
|
685
|
-
description: 'Schema maxLength (maximum 5 characters)',
|
|
686
|
-
component: createLengthTestComponent(undefined, 5),
|
|
687
|
-
assertions: [
|
|
688
|
-
{
|
|
689
|
-
input: getFormData('123456'),
|
|
690
|
-
output: {
|
|
691
|
-
value: getFormData(123456),
|
|
692
|
-
errors: [
|
|
693
|
-
expect.objectContaining({
|
|
694
|
-
text: 'Example number field must be no more than 5 characters'
|
|
695
|
-
})
|
|
696
|
-
]
|
|
697
|
-
}
|
|
698
|
-
},
|
|
699
|
-
{
|
|
700
|
-
input: getFormData('12345'),
|
|
701
|
-
output: { value: getFormData(12345) }
|
|
702
|
-
},
|
|
703
|
-
{
|
|
704
|
-
input: getFormData('123'),
|
|
705
|
-
output: { value: getFormData(123) }
|
|
706
|
-
}
|
|
707
|
-
]
|
|
708
|
-
},
|
|
709
|
-
{
|
|
710
|
-
description:
|
|
711
|
-
'Schema minLength and maxLength (3-8 characters, like latitude)',
|
|
507
|
+
description: 'Schema min and max',
|
|
712
508
|
component: {
|
|
713
|
-
title: '
|
|
714
|
-
shortDescription: 'Latitude',
|
|
509
|
+
title: 'Example number field',
|
|
715
510
|
name: 'myComponent',
|
|
716
511
|
type: ComponentType.NumberField,
|
|
717
|
-
options: {
|
|
718
|
-
customValidationMessages: {
|
|
719
|
-
'number.minPrecision':
|
|
720
|
-
'{{#label}} must have at least {{#minPrecision}} decimal place',
|
|
721
|
-
'number.minLength':
|
|
722
|
-
'{{#label}} must be between 3 and 10 characters',
|
|
723
|
-
'number.maxLength':
|
|
724
|
-
'{{#label}} must be between 3 and 10 characters'
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
schema: {
|
|
728
|
-
min: 49,
|
|
729
|
-
max: 60,
|
|
730
|
-
precision: 7,
|
|
731
|
-
minPrecision: 1,
|
|
732
|
-
minLength: 3,
|
|
733
|
-
maxLength: 10
|
|
734
|
-
}
|
|
735
|
-
} as NumberFieldComponent,
|
|
736
|
-
assertions: [
|
|
737
|
-
{
|
|
738
|
-
input: getFormData('52'),
|
|
739
|
-
output: {
|
|
740
|
-
value: getFormData(52),
|
|
741
|
-
errors: [
|
|
742
|
-
expect.objectContaining({
|
|
743
|
-
text: 'Latitude must have at least 1 decimal place'
|
|
744
|
-
})
|
|
745
|
-
]
|
|
746
|
-
}
|
|
747
|
-
},
|
|
748
|
-
{
|
|
749
|
-
input: getFormData('52.12345678'),
|
|
750
|
-
output: {
|
|
751
|
-
value: getFormData(52.12345678),
|
|
752
|
-
errors: [
|
|
753
|
-
expect.objectContaining({
|
|
754
|
-
text: 'Latitude must have 7 or fewer decimal places'
|
|
755
|
-
})
|
|
756
|
-
]
|
|
757
|
-
}
|
|
758
|
-
},
|
|
759
|
-
{
|
|
760
|
-
input: getFormData('52.1'),
|
|
761
|
-
output: { value: getFormData(52.1) }
|
|
762
|
-
},
|
|
763
|
-
{
|
|
764
|
-
input: getFormData('52.1234'),
|
|
765
|
-
output: { value: getFormData(52.1234) }
|
|
766
|
-
}
|
|
767
|
-
]
|
|
768
|
-
},
|
|
769
|
-
{
|
|
770
|
-
description: 'Schema min and max',
|
|
771
|
-
component: createNumberComponent({
|
|
512
|
+
options: {},
|
|
772
513
|
schema: {
|
|
773
514
|
min: 5,
|
|
774
515
|
max: 8
|
|
775
516
|
}
|
|
776
|
-
}
|
|
517
|
+
} satisfies NumberFieldComponent,
|
|
777
518
|
assertions: [
|
|
778
519
|
{
|
|
779
520
|
input: getFormData('4'),
|
|
@@ -801,7 +542,10 @@ describe('NumberField', () => {
|
|
|
801
542
|
},
|
|
802
543
|
{
|
|
803
544
|
description: 'Custom validation message',
|
|
804
|
-
component:
|
|
545
|
+
component: {
|
|
546
|
+
title: 'Example number field',
|
|
547
|
+
name: 'myComponent',
|
|
548
|
+
type: ComponentType.NumberField,
|
|
805
549
|
options: {
|
|
806
550
|
customValidationMessage: 'This is a custom error',
|
|
807
551
|
customValidationMessages: {
|
|
@@ -810,8 +554,9 @@ describe('NumberField', () => {
|
|
|
810
554
|
'number.min': 'This is not used',
|
|
811
555
|
'number.max': 'This is not used'
|
|
812
556
|
}
|
|
813
|
-
}
|
|
814
|
-
|
|
557
|
+
},
|
|
558
|
+
schema: {}
|
|
559
|
+
} satisfies NumberFieldComponent,
|
|
815
560
|
assertions: [
|
|
816
561
|
{
|
|
817
562
|
input: getFormData(''),
|
|
@@ -941,45 +686,6 @@ describe('NumberField', () => {
|
|
|
941
686
|
}
|
|
942
687
|
]
|
|
943
688
|
},
|
|
944
|
-
{
|
|
945
|
-
description: 'Custom validation message overrides length validation',
|
|
946
|
-
component: {
|
|
947
|
-
title: 'Example number field',
|
|
948
|
-
name: 'myComponent',
|
|
949
|
-
type: ComponentType.NumberField,
|
|
950
|
-
options: {
|
|
951
|
-
customValidationMessage: 'This is a custom length error'
|
|
952
|
-
},
|
|
953
|
-
schema: {
|
|
954
|
-
minLength: 3,
|
|
955
|
-
maxLength: 5
|
|
956
|
-
}
|
|
957
|
-
} satisfies NumberFieldComponent,
|
|
958
|
-
assertions: [
|
|
959
|
-
{
|
|
960
|
-
input: getFormData('12'),
|
|
961
|
-
output: {
|
|
962
|
-
value: getFormData(12),
|
|
963
|
-
errors: [
|
|
964
|
-
expect.objectContaining({
|
|
965
|
-
text: 'This is a custom length error'
|
|
966
|
-
})
|
|
967
|
-
]
|
|
968
|
-
}
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
input: getFormData('123456'),
|
|
972
|
-
output: {
|
|
973
|
-
value: getFormData(123456),
|
|
974
|
-
errors: [
|
|
975
|
-
expect.objectContaining({
|
|
976
|
-
text: 'This is a custom length error'
|
|
977
|
-
})
|
|
978
|
-
]
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
]
|
|
982
|
-
},
|
|
983
689
|
{
|
|
984
690
|
description: 'Optional field',
|
|
985
691
|
component: {
|
|
@@ -1014,202 +720,4 @@ describe('NumberField', () => {
|
|
|
1014
720
|
)
|
|
1015
721
|
})
|
|
1016
722
|
})
|
|
1017
|
-
|
|
1018
|
-
describe('Edge cases', () => {
|
|
1019
|
-
let collection: ComponentCollection
|
|
1020
|
-
|
|
1021
|
-
beforeEach(() => {
|
|
1022
|
-
const def = createNumberComponent({
|
|
1023
|
-
schema: {
|
|
1024
|
-
min: -100,
|
|
1025
|
-
max: 100,
|
|
1026
|
-
precision: 2
|
|
1027
|
-
}
|
|
1028
|
-
})
|
|
1029
|
-
collection = new ComponentCollection([def], { model })
|
|
1030
|
-
})
|
|
1031
|
-
|
|
1032
|
-
it('handles negative numbers correctly', () => {
|
|
1033
|
-
const result = collection.validate(getFormData('-50.5'))
|
|
1034
|
-
expect(result).toEqual({
|
|
1035
|
-
value: getFormData(-50.5)
|
|
1036
|
-
})
|
|
1037
|
-
})
|
|
1038
|
-
|
|
1039
|
-
it('handles zero correctly', () => {
|
|
1040
|
-
const result = collection.validate(getFormData('0'))
|
|
1041
|
-
expect(result).toEqual({
|
|
1042
|
-
value: getFormData(0)
|
|
1043
|
-
})
|
|
1044
|
-
})
|
|
1045
|
-
|
|
1046
|
-
it('handles zero with decimal correctly', () => {
|
|
1047
|
-
const result = collection.validate(getFormData('0.0'))
|
|
1048
|
-
expect(result).toEqual({
|
|
1049
|
-
value: getFormData(0)
|
|
1050
|
-
})
|
|
1051
|
-
})
|
|
1052
|
-
|
|
1053
|
-
it('handles negative zero correctly', () => {
|
|
1054
|
-
const result = collection.validate(getFormData('-0'))
|
|
1055
|
-
expect(result).toEqual({
|
|
1056
|
-
value: getFormData(0)
|
|
1057
|
-
})
|
|
1058
|
-
})
|
|
1059
|
-
|
|
1060
|
-
it('handles scientific notation (parsed as number, may fail range)', () => {
|
|
1061
|
-
// JavaScript parses '1e10' as 10000000000, which exceeds max of 100
|
|
1062
|
-
const result = collection.validate(getFormData('1e10'))
|
|
1063
|
-
expect(result).toEqual({
|
|
1064
|
-
value: getFormData(10000000000),
|
|
1065
|
-
errors: [
|
|
1066
|
-
expect.objectContaining({
|
|
1067
|
-
text: 'Example number field must be 100 or lower'
|
|
1068
|
-
})
|
|
1069
|
-
]
|
|
1070
|
-
})
|
|
1071
|
-
})
|
|
1072
|
-
|
|
1073
|
-
it('handles scientific notation with negative exponent (parsed as number)', () => {
|
|
1074
|
-
// JavaScript parses '1e-5' as 0.00001, which fails precision check (5 decimal places > 2)
|
|
1075
|
-
const result = collection.validate(getFormData('1e-5'))
|
|
1076
|
-
expect(result.value).toEqual(getFormData(0.00001))
|
|
1077
|
-
expect(result.errors).toBeDefined()
|
|
1078
|
-
expect(result.errors?.[0]).toMatchObject({
|
|
1079
|
-
text: 'Example number field must have 2 or fewer decimal places'
|
|
1080
|
-
})
|
|
1081
|
-
})
|
|
1082
|
-
|
|
1083
|
-
it('handles large negative numbers', () => {
|
|
1084
|
-
const result = collection.validate(getFormData('-99.99'))
|
|
1085
|
-
expect(result).toEqual({
|
|
1086
|
-
value: getFormData(-99.99)
|
|
1087
|
-
})
|
|
1088
|
-
})
|
|
1089
|
-
|
|
1090
|
-
it('handles numbers at boundary limits', () => {
|
|
1091
|
-
const maxResult = collection.validate(getFormData('100'))
|
|
1092
|
-
expect(maxResult).toEqual({
|
|
1093
|
-
value: getFormData(100)
|
|
1094
|
-
})
|
|
1095
|
-
|
|
1096
|
-
const minResult = collection.validate(getFormData('-100'))
|
|
1097
|
-
expect(minResult).toEqual({
|
|
1098
|
-
value: getFormData(-100)
|
|
1099
|
-
})
|
|
1100
|
-
})
|
|
1101
|
-
|
|
1102
|
-
describe('with length constraints', () => {
|
|
1103
|
-
beforeEach(() => {
|
|
1104
|
-
const def = createNumberComponent({
|
|
1105
|
-
schema: {
|
|
1106
|
-
min: -9,
|
|
1107
|
-
max: 9,
|
|
1108
|
-
precision: 7,
|
|
1109
|
-
minPrecision: 1,
|
|
1110
|
-
minLength: 2,
|
|
1111
|
-
maxLength: 10
|
|
1112
|
-
},
|
|
1113
|
-
options: {
|
|
1114
|
-
customValidationMessages: {
|
|
1115
|
-
'number.minPrecision':
|
|
1116
|
-
'Example number field must have at least {{minPrecision}} decimal place',
|
|
1117
|
-
'number.precision':
|
|
1118
|
-
'Example number field must have no more than {{limit}} decimal places',
|
|
1119
|
-
'number.minLength':
|
|
1120
|
-
'Example number field must be at least {{minLength}} characters',
|
|
1121
|
-
'number.maxLength':
|
|
1122
|
-
'Example number field must be no more than {{maxLength}} characters'
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
})
|
|
1126
|
-
collection = new ComponentCollection([def], { model })
|
|
1127
|
-
})
|
|
1128
|
-
|
|
1129
|
-
it('validates negative numbers with decimals', () => {
|
|
1130
|
-
const result = collection.validate(getFormData('-5.1234567'))
|
|
1131
|
-
expect(result).toEqual({
|
|
1132
|
-
value: getFormData(-5.1234567)
|
|
1133
|
-
})
|
|
1134
|
-
})
|
|
1135
|
-
|
|
1136
|
-
it('rejects negative numbers that are too short', () => {
|
|
1137
|
-
const result = collection.validate(getFormData('-5'))
|
|
1138
|
-
expect(result.value).toEqual(getFormData(-5))
|
|
1139
|
-
expect(result.errors).toBeDefined()
|
|
1140
|
-
expect(result.errors?.[0].text).toContain('decimal place')
|
|
1141
|
-
})
|
|
1142
|
-
|
|
1143
|
-
it('rejects numbers with too many characters', () => {
|
|
1144
|
-
const result = collection.validate(getFormData('-5.12345678'))
|
|
1145
|
-
expect(result.value).toEqual(getFormData(-5.12345678))
|
|
1146
|
-
expect(result.errors).toBeDefined()
|
|
1147
|
-
expect(result.errors?.[0].text).toContain('decimal places')
|
|
1148
|
-
})
|
|
1149
|
-
})
|
|
1150
|
-
})
|
|
1151
723
|
})
|
|
1152
|
-
|
|
1153
|
-
/**
|
|
1154
|
-
* Factory function to create a default NumberField component with optional overrides
|
|
1155
|
-
*/
|
|
1156
|
-
function createNumberComponent(
|
|
1157
|
-
overrides: Partial<NumberFieldComponent> = {}
|
|
1158
|
-
): NumberFieldComponent {
|
|
1159
|
-
const base = {
|
|
1160
|
-
title: 'Example number field',
|
|
1161
|
-
name: 'myComponent',
|
|
1162
|
-
type: ComponentType.NumberField,
|
|
1163
|
-
options: {},
|
|
1164
|
-
schema: {}
|
|
1165
|
-
} satisfies NumberFieldComponent
|
|
1166
|
-
|
|
1167
|
-
// Deep merge for nested objects like options and schema
|
|
1168
|
-
return {
|
|
1169
|
-
...base,
|
|
1170
|
-
...overrides,
|
|
1171
|
-
options: { ...base.options, ...(overrides.options ?? {}) },
|
|
1172
|
-
schema: { ...base.schema, ...(overrides.schema ?? {}) }
|
|
1173
|
-
} satisfies NumberFieldComponent
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
/**
|
|
1177
|
-
* Helper for precision validation tests
|
|
1178
|
-
*/
|
|
1179
|
-
function createPrecisionTestComponent(
|
|
1180
|
-
minPrecision: number,
|
|
1181
|
-
precision = 7
|
|
1182
|
-
): NumberFieldComponent {
|
|
1183
|
-
const pluralSuffix = minPrecision > 1 ? 's' : ''
|
|
1184
|
-
return createNumberComponent({
|
|
1185
|
-
options: {
|
|
1186
|
-
customValidationMessages: {
|
|
1187
|
-
'number.minPrecision': `{{#label}} must have at least {{#minPrecision}} decimal place${pluralSuffix}`
|
|
1188
|
-
}
|
|
1189
|
-
},
|
|
1190
|
-
schema: { precision, minPrecision }
|
|
1191
|
-
})
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
/**
|
|
1195
|
-
* Helper for length validation tests
|
|
1196
|
-
*/
|
|
1197
|
-
function createLengthTestComponent(
|
|
1198
|
-
minLength?: number,
|
|
1199
|
-
maxLength?: number
|
|
1200
|
-
): NumberFieldComponent {
|
|
1201
|
-
const messages: Record<string, string> = {}
|
|
1202
|
-
if (minLength) {
|
|
1203
|
-
messages['number.minLength'] =
|
|
1204
|
-
'{{#label}} must be at least {{#minLength}} characters'
|
|
1205
|
-
}
|
|
1206
|
-
if (maxLength) {
|
|
1207
|
-
messages['number.maxLength'] =
|
|
1208
|
-
'{{#label}} must be no more than {{#maxLength}} characters'
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
return createNumberComponent({
|
|
1212
|
-
options: { customValidationMessages: messages },
|
|
1213
|
-
schema: { minLength, maxLength }
|
|
1214
|
-
})
|
|
1215
|
-
}
|