@dhis2/ui-forms 10.16.2 → 10.16.3
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/package.json +12 -11
- package/src/CheckboxFieldFF/CheckboxFieldFF.e2e.stories.js +52 -0
- package/src/CheckboxFieldFF/CheckboxFieldFF.js +52 -0
- package/src/CheckboxFieldFF/CheckboxFieldFF.prod.stories.js +142 -0
- package/src/CheckboxFieldFF/features/can_toggle_a_boolean/index.js +19 -0
- package/src/CheckboxFieldFF/features/can_toggle_a_boolean.feature +11 -0
- package/src/CheckboxFieldFF/features/can_toggle_a_value/index.js +21 -0
- package/src/CheckboxFieldFF/features/can_toggle_a_value.feature +11 -0
- package/src/CheckboxFieldFF/features/common/index.js +5 -0
- package/src/CheckboxFieldFF/features/displays_error/index.js +18 -0
- package/src/CheckboxFieldFF/features/displays_error.feature +6 -0
- package/src/FieldGroupFF/FieldGroupFF.js +42 -0
- package/src/FieldGroupFF/FieldGroupFF.prod.stories.js +49 -0
- package/src/FileInputFieldFF/FileInputFieldFF.e2e.stories.js +272 -0
- package/src/FileInputFieldFF/FileInputFieldFF.js +100 -0
- package/src/FileInputFieldFF/FileInputFieldFF.prod.stories.js +95 -0
- package/src/FileInputFieldFF/features/accepts_file/index.js +40 -0
- package/src/FileInputFieldFF/features/accepts_file.feature +13 -0
- package/src/FileInputFieldFF/features/common/index.js +9 -0
- package/src/FileInputFieldFF/features/displays_error/index.js +18 -0
- package/src/FileInputFieldFF/features/displays_error.feature +8 -0
- package/src/InputFieldFF/InputFieldFF.e2e.stories.js +19 -0
- package/src/InputFieldFF/InputFieldFF.js +58 -0
- package/src/InputFieldFF/InputFieldFF.prod.stories.js +102 -0
- package/src/InputFieldFF/features/can_set_a_value/index.js +14 -0
- package/src/InputFieldFF/features/can_set_a_value.feature +6 -0
- package/src/InputFieldFF/features/displays_error/index.js +15 -0
- package/src/InputFieldFF/features/displays_error.feature +6 -0
- package/src/MultiSelectFieldFF/MultiSelectFieldFF.e2e.stories.js +27 -0
- package/src/MultiSelectFieldFF/MultiSelectFieldFF.js +72 -0
- package/src/MultiSelectFieldFF/MultiSelectFieldFF.prod.stories.js +79 -0
- package/src/MultiSelectFieldFF/features/can_set_a_value/index.js +38 -0
- package/src/MultiSelectFieldFF/features/can_set_a_value.feature +14 -0
- package/src/MultiSelectFieldFF/features/common/index.js +7 -0
- package/src/MultiSelectFieldFF/features/displays_error/index.js +10 -0
- package/src/MultiSelectFieldFF/features/displays_error.feature +6 -0
- package/src/RadioFieldFF/RadioFieldFF.e2e.stories.js +39 -0
- package/src/RadioFieldFF/RadioFieldFF.js +52 -0
- package/src/RadioFieldFF/RadioFieldFF.prod.stories.js +104 -0
- package/src/RadioFieldFF/features/can_set_a_value/index.js +24 -0
- package/src/RadioFieldFF/features/can_set_a_value.feature +7 -0
- package/src/RadioFieldFF/features/common/index.js +9 -0
- package/src/RadioFieldFF/features/displays_error/index.js +13 -0
- package/src/RadioFieldFF/features/displays_error.feature +6 -0
- package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.js +172 -0
- package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.prod.stories.js +79 -0
- package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.test.js +82 -0
- package/src/SingleSelectFieldFF/SingleSelectFieldFF.e2e.stories.js +23 -0
- package/src/SingleSelectFieldFF/SingleSelectFieldFF.js +70 -0
- package/src/SingleSelectFieldFF/SingleSelectFieldFF.prod.stories.js +77 -0
- package/src/SingleSelectFieldFF/features/can_set_a_value/index.js +22 -0
- package/src/SingleSelectFieldFF/features/can_set_a_value.feature +7 -0
- package/src/SingleSelectFieldFF/features/common/index.js +6 -0
- package/src/SingleSelectFieldFF/features/displays_error/index.js +10 -0
- package/src/SingleSelectFieldFF/features/displays_error.feature +6 -0
- package/src/SwitchFieldFF/SwitchFieldFF.e2e.stories.js +52 -0
- package/src/SwitchFieldFF/SwitchFieldFF.js +52 -0
- package/src/SwitchFieldFF/SwitchFieldFF.prod.stories.js +148 -0
- package/src/SwitchFieldFF/features/can_toggle_a_boolean/index.js +19 -0
- package/src/SwitchFieldFF/features/can_toggle_a_boolean.feature +11 -0
- package/src/SwitchFieldFF/features/can_toggle_a_value/index.js +21 -0
- package/src/SwitchFieldFF/features/can_toggle_a_value.feature +11 -0
- package/src/SwitchFieldFF/features/common/index.js +5 -0
- package/src/SwitchFieldFF/features/displays_error/index.js +18 -0
- package/src/SwitchFieldFF/features/displays_error.feature +6 -0
- package/src/TextAreaFieldFF/TextAreaFieldFF.e2e.stories.js +23 -0
- package/src/TextAreaFieldFF/TextAreaFieldFF.js +57 -0
- package/src/TextAreaFieldFF/TextAreaFieldFF.prod.stories.js +111 -0
- package/src/TextAreaFieldFF/features/can_set_a_value/index.js +14 -0
- package/src/TextAreaFieldFF/features/can_set_a_value.feature +6 -0
- package/src/TextAreaFieldFF/features/displays_error/index.js +15 -0
- package/src/TextAreaFieldFF/features/displays_error.feature +6 -0
- package/src/__tests__/__snapshots__/index.test.js.snap +65 -0
- package/src/__tests__/index.test.js +37 -0
- package/src/formDecorator.js +80 -0
- package/src/index.js +28 -0
- package/src/locales/ar/translations.json +30 -0
- package/src/locales/ar_IQ/translations.json +30 -0
- package/src/locales/ckb/translations.json +30 -0
- package/src/locales/cs/translations.json +30 -0
- package/src/locales/da/translations.json +30 -0
- package/src/locales/en/translations.json +30 -0
- package/src/locales/es/translations.json +30 -0
- package/src/locales/es_419/translations.json +30 -0
- package/src/locales/fr/translations.json +30 -0
- package/src/locales/hi_IN/translations.json +30 -0
- package/src/locales/id/translations.json +30 -0
- package/src/locales/index.js +84 -0
- package/src/locales/km/translations.json +30 -0
- package/src/locales/ko_KR/translations.json +30 -0
- package/src/locales/lo/translations.json +30 -0
- package/src/locales/my/translations.json +30 -0
- package/src/locales/nb/translations.json +30 -0
- package/src/locales/nl/translations.json +30 -0
- package/src/locales/prs/translations.json +30 -0
- package/src/locales/ps/translations.json +30 -0
- package/src/locales/pt/translations.json +30 -0
- package/src/locales/pt_BR/translations.json +30 -0
- package/src/locales/ro/translations.json +30 -0
- package/src/locales/ru/translations.json +30 -0
- package/src/locales/si/translations.json +30 -0
- package/src/locales/sv/translations.json +30 -0
- package/src/locales/tet/translations.json +30 -0
- package/src/locales/tg/translations.json +30 -0
- package/src/locales/uk/translations.json +30 -0
- package/src/locales/ur/translations.json +30 -0
- package/src/locales/uz_Latn/translations.json +30 -0
- package/src/locales/uz_UZ_Cyrl/translations.json +30 -0
- package/src/locales/uz_UZ_Latn/translations.json +30 -0
- package/src/locales/vi/translations.json +30 -0
- package/src/locales/zh/translations.json +30 -0
- package/src/locales/zh_CN/translations.json +30 -0
- package/src/shared/helpers/createBlurHandler.js +9 -0
- package/src/shared/helpers/createChangeHandler.js +21 -0
- package/src/shared/helpers/createFocusHandler.js +9 -0
- package/src/shared/helpers/createSelectChangeHandler.js +6 -0
- package/src/shared/helpers/createToggleChangeHandler.js +9 -0
- package/src/shared/helpers/getValidationText.js +21 -0
- package/src/shared/helpers/hasError.js +3 -0
- package/src/shared/helpers/isLoading.js +4 -0
- package/src/shared/helpers/isValid.js +4 -0
- package/src/shared/helpers.js +9 -0
- package/src/shared/propTypes.js +48 -0
- package/src/transformers/arrayWithIdObjects.js +8 -0
- package/src/transformers/index.js +1 -0
- package/src/validators/__tests__/alphaNumeric.test.js +29 -0
- package/src/validators/__tests__/boolean.test.js +23 -0
- package/src/validators/__tests__/composeValidators.test.js +23 -0
- package/src/validators/__tests__/createCharacterLengthRange.test.js +59 -0
- package/src/validators/__tests__/createEqualTo.test.js +43 -0
- package/src/validators/__tests__/createMaxCharacterLength.test.js +24 -0
- package/src/validators/__tests__/createMaxNumber.test.js +21 -0
- package/src/validators/__tests__/createMinCharacterLength.test.js +24 -0
- package/src/validators/__tests__/createMinNumber.test.js +21 -0
- package/src/validators/__tests__/createNumberRange.test.js +68 -0
- package/src/validators/__tests__/createPattern.test.js +40 -0
- package/src/validators/__tests__/dhis2Password.test.js +51 -0
- package/src/validators/__tests__/dhis2Username.test.js +75 -0
- package/src/validators/__tests__/email.test.js +83 -0
- package/src/validators/__tests__/hasValue.test.js +21 -0
- package/src/validators/__tests__/integer.test.js +48 -0
- package/src/validators/__tests__/internationalPhoneNumber.test.js +49 -0
- package/src/validators/__tests__/number.test.js +39 -0
- package/src/validators/__tests__/string.test.js +29 -0
- package/src/validators/__tests__/url.test.js +106 -0
- package/src/validators/alphaNumeric.js +15 -0
- package/src/validators/boolean.js +11 -0
- package/src/validators/composeValidators.js +8 -0
- package/src/validators/createCharacterLengthRange.js +27 -0
- package/src/validators/createEqualTo.js +16 -0
- package/src/validators/createMaxCharacterLength.js +13 -0
- package/src/validators/createMaxNumber.js +13 -0
- package/src/validators/createMinCharacterLength.js +13 -0
- package/src/validators/createMinNumber.js +13 -0
- package/src/validators/createNumberRange.js +28 -0
- package/src/validators/createPattern.js +22 -0
- package/src/validators/dhis2Password.js +81 -0
- package/src/validators/dhis2Username.js +16 -0
- package/src/validators/email.js +38 -0
- package/src/validators/hasValue.js +8 -0
- package/src/validators/helpers/index.js +23 -0
- package/src/validators/index.js +20 -0
- package/src/validators/integer.js +20 -0
- package/src/validators/internationalPhoneNumber.js +56 -0
- package/src/validators/number.js +9 -0
- package/src/validators/string.js +9 -0
- package/src/validators/test-helpers/index.js +21 -0
- package/src/validators/url.js +15 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { dhis2Username, invalidUsernameMessage } from '../dhis2Username.js'
|
|
2
|
+
import {
|
|
3
|
+
testValidatorValues,
|
|
4
|
+
allowsEmptyValues,
|
|
5
|
+
} from '../test-helpers/index.js'
|
|
6
|
+
|
|
7
|
+
describe('validator: dhis2Username', () => {
|
|
8
|
+
allowsEmptyValues(dhis2Username)
|
|
9
|
+
|
|
10
|
+
describe('constrains length of username to between 4 and 255 characters long', () => {
|
|
11
|
+
testValidatorValues(dhis2Username, undefined, [
|
|
12
|
+
's'.repeat(4),
|
|
13
|
+
's'.repeat(255),
|
|
14
|
+
'valid_username',
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
18
|
+
'1',
|
|
19
|
+
's',
|
|
20
|
+
's'.repeat(256),
|
|
21
|
+
])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('does not allow usernames to start with _, -, . or @', () => {
|
|
25
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
26
|
+
'_xxx',
|
|
27
|
+
'-xxx',
|
|
28
|
+
'.xxx',
|
|
29
|
+
'@xxx',
|
|
30
|
+
])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('does not allow usernames to end with _, -, . or @', () => {
|
|
34
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
35
|
+
'xxx_',
|
|
36
|
+
'xxx-',
|
|
37
|
+
'xxx.',
|
|
38
|
+
'xxx@',
|
|
39
|
+
])
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('does not allow usernames to contain __, --, .. or @@', () => {
|
|
43
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
44
|
+
'xx__xx',
|
|
45
|
+
'xx--xx',
|
|
46
|
+
'xx..xx',
|
|
47
|
+
'xx@@xx',
|
|
48
|
+
])
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('constrains characters in usernames to [a-z0-9._@]', () => {
|
|
52
|
+
testValidatorValues(dhis2Username, undefined, [
|
|
53
|
+
'v@lid_user.name',
|
|
54
|
+
'v@lid-user.name',
|
|
55
|
+
'123another_v@lid_usern@me',
|
|
56
|
+
'UPPER_CASE',
|
|
57
|
+
'lower@ca.se',
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
61
|
+
'あいうえお',
|
|
62
|
+
'some_username^%&*(',
|
|
63
|
+
])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('rejects non-string data types', () => {
|
|
67
|
+
testValidatorValues(dhis2Username, invalidUsernameMessage, [
|
|
68
|
+
1,
|
|
69
|
+
true,
|
|
70
|
+
{},
|
|
71
|
+
[],
|
|
72
|
+
() => {},
|
|
73
|
+
])
|
|
74
|
+
})
|
|
75
|
+
})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { email, invalidEmailMessage } from '../email.js'
|
|
2
|
+
import {
|
|
3
|
+
testValidatorValues,
|
|
4
|
+
allowsEmptyValues,
|
|
5
|
+
} from '../test-helpers/index.js'
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* A comprehensive list technically valid and invalid email addresses was
|
|
9
|
+
* taken from:
|
|
10
|
+
* https://codefool.tumblr.com/post/15288874550/list-of-valid-and-invalid-email-addresses
|
|
11
|
+
*
|
|
12
|
+
* Our chosen regex does not work correctly in each case, but on balance
|
|
13
|
+
* it performs pretty well: all plausible email addresses are accepted
|
|
14
|
+
* and most malformed email addresses are rejected.
|
|
15
|
+
*
|
|
16
|
+
* I have kept the original list of values and have simply commented out
|
|
17
|
+
* the ones that are not evaluated correctly by our regex.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
describe('validator: email', () => {
|
|
21
|
+
allowsEmptyValues(email)
|
|
22
|
+
|
|
23
|
+
describe('allows valid email addresses', () => {
|
|
24
|
+
/*
|
|
25
|
+
* Items that have been commented out below are FALSELY REJECTED by the chosen regex
|
|
26
|
+
*/
|
|
27
|
+
testValidatorValues(email, undefined, [
|
|
28
|
+
'email@example.com',
|
|
29
|
+
'firstname.lastname@example.com',
|
|
30
|
+
'email@subdomain.example.com',
|
|
31
|
+
'firstname+lastname@example.com',
|
|
32
|
+
// 'email@123.123.123.123',
|
|
33
|
+
'email@[123.123.123.123]',
|
|
34
|
+
'"email"@example.com',
|
|
35
|
+
'1234567890@example.com',
|
|
36
|
+
'email@example-one.com',
|
|
37
|
+
'_______@example.com',
|
|
38
|
+
'email@example.name',
|
|
39
|
+
'email@example.museum',
|
|
40
|
+
'email@example.co.jp',
|
|
41
|
+
'firstname-lastname@example.com',
|
|
42
|
+
|
|
43
|
+
/* very strange but technically valid addresses */
|
|
44
|
+
// 'much."more unusual"@example.com',
|
|
45
|
+
// 'very.unusual."@".unusual.com@example.com',
|
|
46
|
+
// 'very."(),:;<>[]".VERY."very@\\\\\\ "very".unusual@strange.example.com',
|
|
47
|
+
])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('rejects invalid email addresses', () => {
|
|
51
|
+
/*
|
|
52
|
+
* Items that have been commented out below are FALSELY ACCEPTED by the chosen regex
|
|
53
|
+
*/
|
|
54
|
+
testValidatorValues(email, invalidEmailMessage, [
|
|
55
|
+
'plainaddress',
|
|
56
|
+
'#@%^%#$@#$@#.com',
|
|
57
|
+
'@example.com',
|
|
58
|
+
'Joe Smith <email@example.com>',
|
|
59
|
+
'email.example.com',
|
|
60
|
+
'email@example@example.com',
|
|
61
|
+
'.email@example.com',
|
|
62
|
+
'email.@example.com',
|
|
63
|
+
'email..email@example.com',
|
|
64
|
+
/*
|
|
65
|
+
* I think this false positive below may actualy be correct behaviour,
|
|
66
|
+
* see https://en.wikipedia.org/wiki/International_email)
|
|
67
|
+
*/
|
|
68
|
+
// 'あいうえお@example.com'
|
|
69
|
+
'email@example.com (Joe Smith)',
|
|
70
|
+
'email@example',
|
|
71
|
+
// 'email@-example.com',
|
|
72
|
+
// 'email@example.web',
|
|
73
|
+
'email@111.222.333.44444',
|
|
74
|
+
'email@example..com',
|
|
75
|
+
'Abc..123@example.com',
|
|
76
|
+
|
|
77
|
+
/* very strange invalid addresses */
|
|
78
|
+
'"(),:;<>[]@example.com',
|
|
79
|
+
'just"not"right@example.com',
|
|
80
|
+
'this is"really"not\\\\allowed@example.com',
|
|
81
|
+
])
|
|
82
|
+
})
|
|
83
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { hasValue, hasValueMessage } from '../hasValue.js'
|
|
2
|
+
import { testValidatorValues } from '../test-helpers/index.js'
|
|
3
|
+
|
|
4
|
+
describe('validator: hasValue', () => {
|
|
5
|
+
describe('should return undefined for allowed values', () => {
|
|
6
|
+
testValidatorValues(hasValue, undefined, [
|
|
7
|
+
'test',
|
|
8
|
+
false,
|
|
9
|
+
true,
|
|
10
|
+
0,
|
|
11
|
+
1,
|
|
12
|
+
{},
|
|
13
|
+
[],
|
|
14
|
+
new Date(),
|
|
15
|
+
])
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
describe('should return the error message for disallowed values', () => {
|
|
19
|
+
testValidatorValues(hasValue, hasValueMessage, ['', undefined, null])
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { integer, invalidIntegerMessage } from '../integer.js'
|
|
2
|
+
import {
|
|
3
|
+
testValidatorValues,
|
|
4
|
+
allowsEmptyValues,
|
|
5
|
+
} from '../test-helpers/index.js'
|
|
6
|
+
|
|
7
|
+
describe('validator: integer', () => {
|
|
8
|
+
allowsEmptyValues(integer)
|
|
9
|
+
|
|
10
|
+
describe('allows integers and string representations of integers', () => {
|
|
11
|
+
testValidatorValues(integer, undefined, [
|
|
12
|
+
-2,
|
|
13
|
+
0,
|
|
14
|
+
2,
|
|
15
|
+
10000,
|
|
16
|
+
'-2',
|
|
17
|
+
'0',
|
|
18
|
+
'2',
|
|
19
|
+
'10000',
|
|
20
|
+
12e4,
|
|
21
|
+
])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('rejects other data types and leading zeros', () => {
|
|
25
|
+
testValidatorValues(integer, invalidIntegerMessage, [
|
|
26
|
+
'text',
|
|
27
|
+
'014',
|
|
28
|
+
true,
|
|
29
|
+
{},
|
|
30
|
+
[],
|
|
31
|
+
() => {},
|
|
32
|
+
])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('rejects floats and string representations of floats', () => {
|
|
36
|
+
testValidatorValues(integer, invalidIntegerMessage, [
|
|
37
|
+
0.23456,
|
|
38
|
+
5.987,
|
|
39
|
+
1e-12,
|
|
40
|
+
'4.0',
|
|
41
|
+
'4.000',
|
|
42
|
+
'4,0',
|
|
43
|
+
'0.23456',
|
|
44
|
+
'5.987',
|
|
45
|
+
'1e-12',
|
|
46
|
+
])
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internationalPhoneNumber,
|
|
3
|
+
invalidInternationalPhoneNumberMessage,
|
|
4
|
+
} from '../internationalPhoneNumber.js'
|
|
5
|
+
import {
|
|
6
|
+
testValidatorValues,
|
|
7
|
+
allowsEmptyValues,
|
|
8
|
+
} from '../test-helpers/index.js'
|
|
9
|
+
|
|
10
|
+
describe('validator: internationalPhoneNumber', () => {
|
|
11
|
+
allowsEmptyValues(internationalPhoneNumber)
|
|
12
|
+
|
|
13
|
+
describe('allows valid phone numbers', () => {
|
|
14
|
+
testValidatorValues(internationalPhoneNumber, undefined, [
|
|
15
|
+
'+31(0)725111889',
|
|
16
|
+
'068.468.0076',
|
|
17
|
+
'1-724-187-8238',
|
|
18
|
+
'(967) 211-7114',
|
|
19
|
+
'(978) 242-4017',
|
|
20
|
+
'105-535-1160',
|
|
21
|
+
'147-357-7565',
|
|
22
|
+
'(974) 309-3992',
|
|
23
|
+
'+1-228-630-0639',
|
|
24
|
+
'917.258.5059',
|
|
25
|
+
'888-814-8989',
|
|
26
|
+
])
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('rejects non-string values', () => {
|
|
30
|
+
testValidatorValues(
|
|
31
|
+
internationalPhoneNumber,
|
|
32
|
+
invalidInternationalPhoneNumberMessage,
|
|
33
|
+
[true, 3, {}, [], () => {}]
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('rejects invalid phone numbers', () => {
|
|
38
|
+
testValidatorValues(
|
|
39
|
+
internationalPhoneNumber,
|
|
40
|
+
invalidInternationalPhoneNumberMessage,
|
|
41
|
+
[
|
|
42
|
+
'sometext123', // text
|
|
43
|
+
'+3172%^$#%*182838485868', // special characters
|
|
44
|
+
'+31725111889101112131415', // too long
|
|
45
|
+
'0031_72_5111889', // bad separators
|
|
46
|
+
]
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { number, invalidNumberMessage } from '../number.js'
|
|
2
|
+
import {
|
|
3
|
+
testValidatorValues,
|
|
4
|
+
allowsEmptyValues,
|
|
5
|
+
} from '../test-helpers/index.js'
|
|
6
|
+
|
|
7
|
+
describe('validator: number', () => {
|
|
8
|
+
allowsEmptyValues(number)
|
|
9
|
+
|
|
10
|
+
describe('allows numbers and string representations of numbers', () => {
|
|
11
|
+
testValidatorValues(number, undefined, [
|
|
12
|
+
-2,
|
|
13
|
+
0,
|
|
14
|
+
2,
|
|
15
|
+
10000,
|
|
16
|
+
'-2',
|
|
17
|
+
'0',
|
|
18
|
+
'2',
|
|
19
|
+
'10000',
|
|
20
|
+
12e4,
|
|
21
|
+
0.23456,
|
|
22
|
+
5.987,
|
|
23
|
+
1e-12,
|
|
24
|
+
'0.23456',
|
|
25
|
+
'5.987',
|
|
26
|
+
'1e-12',
|
|
27
|
+
])
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('rejects other data types', () => {
|
|
31
|
+
testValidatorValues(number, invalidNumberMessage, [
|
|
32
|
+
'text',
|
|
33
|
+
true,
|
|
34
|
+
{},
|
|
35
|
+
[],
|
|
36
|
+
() => {},
|
|
37
|
+
])
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { string, invalidStringMessage } from '../string.js'
|
|
2
|
+
import {
|
|
3
|
+
testValidatorValues,
|
|
4
|
+
allowsEmptyValues,
|
|
5
|
+
} from '../test-helpers/index.js'
|
|
6
|
+
|
|
7
|
+
describe('validator: string', () => {
|
|
8
|
+
allowsEmptyValues(string)
|
|
9
|
+
|
|
10
|
+
describe('allows strings', () => {
|
|
11
|
+
testValidatorValues(string, undefined, [
|
|
12
|
+
'text',
|
|
13
|
+
'1',
|
|
14
|
+
'0.15',
|
|
15
|
+
'true',
|
|
16
|
+
'false',
|
|
17
|
+
])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('rejects other data types', () => {
|
|
21
|
+
testValidatorValues(string, invalidStringMessage, [
|
|
22
|
+
1,
|
|
23
|
+
true,
|
|
24
|
+
{},
|
|
25
|
+
[],
|
|
26
|
+
() => {},
|
|
27
|
+
])
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
testValidatorValues,
|
|
3
|
+
allowsEmptyValues,
|
|
4
|
+
} from '../test-helpers/index.js'
|
|
5
|
+
import { url, invalidUrlMessage } from '../url.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* List of valid and invalid URIs was sourced from
|
|
9
|
+
* https://formvalidation.io/guide/validators/uri
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
describe('validator: url', () => {
|
|
13
|
+
allowsEmptyValues(url)
|
|
14
|
+
|
|
15
|
+
describe('allows valid URLs', () => {
|
|
16
|
+
testValidatorValues(url, undefined, [
|
|
17
|
+
'http://foo.com/blah_blah',
|
|
18
|
+
'http://foo.com/blah_blah/',
|
|
19
|
+
'http://foo.com/blah_blah_(wikipedia)',
|
|
20
|
+
'http://foo.com/blah_blah_(wikipedia)_(again)',
|
|
21
|
+
'http://www.example.com/wpstyle/?p=364',
|
|
22
|
+
'https://www.example.com/foo/?bar=baz&inga=42&quux',
|
|
23
|
+
'http://✪df.ws/123',
|
|
24
|
+
'http://userid:password@example.com:8080',
|
|
25
|
+
'http://userid:password@example.com:8080/',
|
|
26
|
+
'http://userid@example.com',
|
|
27
|
+
'http://userid@example.com/',
|
|
28
|
+
'http://userid@example.com:8080',
|
|
29
|
+
'http://userid@example.com:8080/',
|
|
30
|
+
'http://userid:password@example.com',
|
|
31
|
+
'http://userid:password@example.com/',
|
|
32
|
+
'http://142.42.1.1/',
|
|
33
|
+
'http://142.42.1.1:8080/',
|
|
34
|
+
'http://➡.ws/䨹',
|
|
35
|
+
'http://⌘.ws',
|
|
36
|
+
'http://⌘.ws/',
|
|
37
|
+
'http://foo.com/blah_(wikipedia)#cite-1',
|
|
38
|
+
'http://foo.com/blah_(wikipedia)_blah#cite-1',
|
|
39
|
+
'http://foo.com/unicode_(✪)_in_parens',
|
|
40
|
+
'http://foo.com/(something)?after=parens',
|
|
41
|
+
'http://☺.damowmow.com/',
|
|
42
|
+
'http://code.google.com/events/#&product=browser',
|
|
43
|
+
'http://j.mp',
|
|
44
|
+
'ftp://foo.bar/baz',
|
|
45
|
+
'http://foo.bar/?q=Test%20URL-encoded%20stuff',
|
|
46
|
+
'http://مثال.إختبار',
|
|
47
|
+
'http://例子.测试',
|
|
48
|
+
'http://उदाहरण.परीक्षा',
|
|
49
|
+
'http://-.~_!$&()*+,;=:%40:80%2f::::::@example.com',
|
|
50
|
+
'http://1337.net',
|
|
51
|
+
'http://a.b-c.de',
|
|
52
|
+
'http://223.255.255.254',
|
|
53
|
+
/*
|
|
54
|
+
* The one below is classified as valid by our regex
|
|
55
|
+
* but it was originally in the list of invalid urls
|
|
56
|
+
* I think it was misclassified, so moved it into the valid list. See:
|
|
57
|
+
* https://www.domainit.com/support/faq.mhtml?category=Domain_FAQ&question=9
|
|
58
|
+
* "A little known fact is that you CAN have multiple dashes right next to each other."
|
|
59
|
+
*/
|
|
60
|
+
'http://a.b--c.de/',
|
|
61
|
+
])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('rejects invalid URLs', () => {
|
|
65
|
+
testValidatorValues(url, invalidUrlMessage, [
|
|
66
|
+
'http://',
|
|
67
|
+
'http://.',
|
|
68
|
+
'http://..',
|
|
69
|
+
'http://../',
|
|
70
|
+
'http://?',
|
|
71
|
+
'http://??',
|
|
72
|
+
'http://??/',
|
|
73
|
+
'http://#',
|
|
74
|
+
'http://##',
|
|
75
|
+
'http://##/',
|
|
76
|
+
'http://foo.bar?q=Spaces should be encoded',
|
|
77
|
+
'//',
|
|
78
|
+
'//a',
|
|
79
|
+
'///a',
|
|
80
|
+
'///',
|
|
81
|
+
'http:///a',
|
|
82
|
+
'foo.com',
|
|
83
|
+
'rdar://1234',
|
|
84
|
+
'h://test',
|
|
85
|
+
'http:// shouldfail.com',
|
|
86
|
+
':// should fail',
|
|
87
|
+
'http://foo.bar/foo(bar)baz quux',
|
|
88
|
+
'ftps://foo.bar/',
|
|
89
|
+
'http://-error-.invalid/',
|
|
90
|
+
'http://-a.b.co',
|
|
91
|
+
'http://a.b-.co',
|
|
92
|
+
'http://0.0.0.0',
|
|
93
|
+
'http://10.1.1.0',
|
|
94
|
+
'http://10.1.1.255',
|
|
95
|
+
'http://224.1.1.1',
|
|
96
|
+
'http://1.1.1.1.1',
|
|
97
|
+
'http://123.123.123',
|
|
98
|
+
'http://3628126748',
|
|
99
|
+
'http://.www.foo.bar/',
|
|
100
|
+
'http://www.foo.bar./',
|
|
101
|
+
'http://.www.foo.bar./',
|
|
102
|
+
'http://10.1.1.1',
|
|
103
|
+
'http://10.1.1.',
|
|
104
|
+
])
|
|
105
|
+
})
|
|
106
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { isEmpty, isString } from './helpers/index.js'
|
|
3
|
+
|
|
4
|
+
const ALPHA_NUMERIC_PATTERN = /^[a-z0-9 ]*$/i
|
|
5
|
+
|
|
6
|
+
const invalidAlphaNumericMessage = i18n.t(
|
|
7
|
+
'Please provide an alpha-numeric value'
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
const alphaNumeric = (value) =>
|
|
11
|
+
isEmpty(value) || (isString(value) && ALPHA_NUMERIC_PATTERN.test(value))
|
|
12
|
+
? undefined
|
|
13
|
+
: invalidAlphaNumericMessage
|
|
14
|
+
|
|
15
|
+
export { alphaNumeric, invalidAlphaNumericMessage }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { isEmpty } from './helpers/index.js'
|
|
3
|
+
|
|
4
|
+
const invalidBooleanMessage = i18n.t('Please provide a boolean value')
|
|
5
|
+
|
|
6
|
+
const boolean = (value) =>
|
|
7
|
+
isEmpty(value) || typeof value === 'boolean'
|
|
8
|
+
? undefined
|
|
9
|
+
: invalidBooleanMessage
|
|
10
|
+
|
|
11
|
+
export { boolean, invalidBooleanMessage }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import {
|
|
3
|
+
isEmpty,
|
|
4
|
+
isString,
|
|
5
|
+
isInRange,
|
|
6
|
+
requireArgument,
|
|
7
|
+
} from './helpers/index.js'
|
|
8
|
+
|
|
9
|
+
const createCharacterLengthRange = (lowerBound, upperBound, customMessage) => {
|
|
10
|
+
requireArgument(lowerBound, 'number')
|
|
11
|
+
requireArgument(upperBound, 'number')
|
|
12
|
+
|
|
13
|
+
const errorMessage =
|
|
14
|
+
customMessage ||
|
|
15
|
+
i18n.t(
|
|
16
|
+
'Please enter between {{lowerBound}} and {{upperBound}} characters',
|
|
17
|
+
{ lowerBound, upperBound }
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return (value) =>
|
|
21
|
+
isEmpty(value) ||
|
|
22
|
+
(isString(value) && isInRange(lowerBound, upperBound, value.length))
|
|
23
|
+
? undefined
|
|
24
|
+
: errorMessage
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { createCharacterLengthRange }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { isEmpty, requireArgument } from './helpers/index.js'
|
|
3
|
+
|
|
4
|
+
const createEqualTo = (key, description) => {
|
|
5
|
+
requireArgument(key, 'string')
|
|
6
|
+
|
|
7
|
+
const errorMessage = i18n.t(
|
|
8
|
+
'Please make sure the value of this input matches the value in "{{otherField}}".',
|
|
9
|
+
{ otherField: description || key }
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
return (value, allValues) =>
|
|
13
|
+
isEmpty(value) || value === allValues[key] ? undefined : errorMessage
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { createEqualTo }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { createCharacterLengthRange } from './createCharacterLengthRange.js'
|
|
3
|
+
|
|
4
|
+
const createMaxCharacterLength = (upperBound) =>
|
|
5
|
+
createCharacterLengthRange(
|
|
6
|
+
0,
|
|
7
|
+
upperBound,
|
|
8
|
+
i18n.t('Please enter a maximum of {{upperBound}} characters', {
|
|
9
|
+
upperBound,
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export { createMaxCharacterLength }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { createNumberRange } from './createNumberRange.js'
|
|
3
|
+
|
|
4
|
+
const createMaxNumber = (upperBound) =>
|
|
5
|
+
createNumberRange(
|
|
6
|
+
-Infinity,
|
|
7
|
+
upperBound,
|
|
8
|
+
i18n.t('Please enter a number with a maximum of {{upperBound}}', {
|
|
9
|
+
upperBound,
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export { createMaxNumber }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { createCharacterLengthRange } from './createCharacterLengthRange.js'
|
|
3
|
+
|
|
4
|
+
const createMinCharacterLength = (lowerBound) =>
|
|
5
|
+
createCharacterLengthRange(
|
|
6
|
+
lowerBound,
|
|
7
|
+
Infinity,
|
|
8
|
+
i18n.t('Please enter at least {{lowerBound}} characters', {
|
|
9
|
+
lowerBound,
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export { createMinCharacterLength }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { createNumberRange } from './createNumberRange.js'
|
|
3
|
+
|
|
4
|
+
const createMinNumber = (lowerBound) =>
|
|
5
|
+
createNumberRange(
|
|
6
|
+
lowerBound,
|
|
7
|
+
Infinity,
|
|
8
|
+
i18n.t('Please enter a number of at least {{lowerBound}}', {
|
|
9
|
+
lowerBound,
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export { createMinNumber }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import {
|
|
3
|
+
isEmpty,
|
|
4
|
+
isNumeric,
|
|
5
|
+
toNumber,
|
|
6
|
+
isInRange,
|
|
7
|
+
requireArgument,
|
|
8
|
+
} from './helpers/index.js'
|
|
9
|
+
|
|
10
|
+
const createNumberRange = (lowerBound, upperBound, customMessage) => {
|
|
11
|
+
requireArgument(lowerBound, 'number')
|
|
12
|
+
requireArgument(upperBound, 'number')
|
|
13
|
+
|
|
14
|
+
const errorMessage =
|
|
15
|
+
customMessage ||
|
|
16
|
+
i18n.t(
|
|
17
|
+
'Number cannot be less than {{lowerBound}} or more than {{upperBound}}',
|
|
18
|
+
{ lowerBound, upperBound }
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
return (value) =>
|
|
22
|
+
isEmpty(value) ||
|
|
23
|
+
(isNumeric(value) && isInRange(lowerBound, upperBound, toNumber(value)))
|
|
24
|
+
? undefined
|
|
25
|
+
: errorMessage
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { createNumberRange }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import i18n from '../locales/index.js'
|
|
2
|
+
import { isEmpty, isString } from './helpers/index.js'
|
|
3
|
+
|
|
4
|
+
const invalidPatternMessage =
|
|
5
|
+
'The first argument passed to createPattern was not a valid regex'
|
|
6
|
+
|
|
7
|
+
const createPattern = (pattern, message) => {
|
|
8
|
+
if (!(pattern instanceof RegExp)) {
|
|
9
|
+
throw new Error(invalidPatternMessage)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return (value) =>
|
|
13
|
+
isEmpty(value) || (isString(value) && pattern.test(value))
|
|
14
|
+
? undefined
|
|
15
|
+
: message ||
|
|
16
|
+
i18n.t(
|
|
17
|
+
'Please make sure the value of this input matches the pattern {{patternString}}.',
|
|
18
|
+
{ patternString: pattern.toString() }
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { createPattern, invalidPatternMessage }
|