@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.
Files changed (168) hide show
  1. package/package.json +12 -11
  2. package/src/CheckboxFieldFF/CheckboxFieldFF.e2e.stories.js +52 -0
  3. package/src/CheckboxFieldFF/CheckboxFieldFF.js +52 -0
  4. package/src/CheckboxFieldFF/CheckboxFieldFF.prod.stories.js +142 -0
  5. package/src/CheckboxFieldFF/features/can_toggle_a_boolean/index.js +19 -0
  6. package/src/CheckboxFieldFF/features/can_toggle_a_boolean.feature +11 -0
  7. package/src/CheckboxFieldFF/features/can_toggle_a_value/index.js +21 -0
  8. package/src/CheckboxFieldFF/features/can_toggle_a_value.feature +11 -0
  9. package/src/CheckboxFieldFF/features/common/index.js +5 -0
  10. package/src/CheckboxFieldFF/features/displays_error/index.js +18 -0
  11. package/src/CheckboxFieldFF/features/displays_error.feature +6 -0
  12. package/src/FieldGroupFF/FieldGroupFF.js +42 -0
  13. package/src/FieldGroupFF/FieldGroupFF.prod.stories.js +49 -0
  14. package/src/FileInputFieldFF/FileInputFieldFF.e2e.stories.js +272 -0
  15. package/src/FileInputFieldFF/FileInputFieldFF.js +100 -0
  16. package/src/FileInputFieldFF/FileInputFieldFF.prod.stories.js +95 -0
  17. package/src/FileInputFieldFF/features/accepts_file/index.js +40 -0
  18. package/src/FileInputFieldFF/features/accepts_file.feature +13 -0
  19. package/src/FileInputFieldFF/features/common/index.js +9 -0
  20. package/src/FileInputFieldFF/features/displays_error/index.js +18 -0
  21. package/src/FileInputFieldFF/features/displays_error.feature +8 -0
  22. package/src/InputFieldFF/InputFieldFF.e2e.stories.js +19 -0
  23. package/src/InputFieldFF/InputFieldFF.js +58 -0
  24. package/src/InputFieldFF/InputFieldFF.prod.stories.js +102 -0
  25. package/src/InputFieldFF/features/can_set_a_value/index.js +14 -0
  26. package/src/InputFieldFF/features/can_set_a_value.feature +6 -0
  27. package/src/InputFieldFF/features/displays_error/index.js +15 -0
  28. package/src/InputFieldFF/features/displays_error.feature +6 -0
  29. package/src/MultiSelectFieldFF/MultiSelectFieldFF.e2e.stories.js +27 -0
  30. package/src/MultiSelectFieldFF/MultiSelectFieldFF.js +72 -0
  31. package/src/MultiSelectFieldFF/MultiSelectFieldFF.prod.stories.js +79 -0
  32. package/src/MultiSelectFieldFF/features/can_set_a_value/index.js +38 -0
  33. package/src/MultiSelectFieldFF/features/can_set_a_value.feature +14 -0
  34. package/src/MultiSelectFieldFF/features/common/index.js +7 -0
  35. package/src/MultiSelectFieldFF/features/displays_error/index.js +10 -0
  36. package/src/MultiSelectFieldFF/features/displays_error.feature +6 -0
  37. package/src/RadioFieldFF/RadioFieldFF.e2e.stories.js +39 -0
  38. package/src/RadioFieldFF/RadioFieldFF.js +52 -0
  39. package/src/RadioFieldFF/RadioFieldFF.prod.stories.js +104 -0
  40. package/src/RadioFieldFF/features/can_set_a_value/index.js +24 -0
  41. package/src/RadioFieldFF/features/can_set_a_value.feature +7 -0
  42. package/src/RadioFieldFF/features/common/index.js +9 -0
  43. package/src/RadioFieldFF/features/displays_error/index.js +13 -0
  44. package/src/RadioFieldFF/features/displays_error.feature +6 -0
  45. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.js +172 -0
  46. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.prod.stories.js +79 -0
  47. package/src/SimpleSingleSelectFieldFF/SimpleSingleSelectFieldFF.test.js +82 -0
  48. package/src/SingleSelectFieldFF/SingleSelectFieldFF.e2e.stories.js +23 -0
  49. package/src/SingleSelectFieldFF/SingleSelectFieldFF.js +70 -0
  50. package/src/SingleSelectFieldFF/SingleSelectFieldFF.prod.stories.js +77 -0
  51. package/src/SingleSelectFieldFF/features/can_set_a_value/index.js +22 -0
  52. package/src/SingleSelectFieldFF/features/can_set_a_value.feature +7 -0
  53. package/src/SingleSelectFieldFF/features/common/index.js +6 -0
  54. package/src/SingleSelectFieldFF/features/displays_error/index.js +10 -0
  55. package/src/SingleSelectFieldFF/features/displays_error.feature +6 -0
  56. package/src/SwitchFieldFF/SwitchFieldFF.e2e.stories.js +52 -0
  57. package/src/SwitchFieldFF/SwitchFieldFF.js +52 -0
  58. package/src/SwitchFieldFF/SwitchFieldFF.prod.stories.js +148 -0
  59. package/src/SwitchFieldFF/features/can_toggle_a_boolean/index.js +19 -0
  60. package/src/SwitchFieldFF/features/can_toggle_a_boolean.feature +11 -0
  61. package/src/SwitchFieldFF/features/can_toggle_a_value/index.js +21 -0
  62. package/src/SwitchFieldFF/features/can_toggle_a_value.feature +11 -0
  63. package/src/SwitchFieldFF/features/common/index.js +5 -0
  64. package/src/SwitchFieldFF/features/displays_error/index.js +18 -0
  65. package/src/SwitchFieldFF/features/displays_error.feature +6 -0
  66. package/src/TextAreaFieldFF/TextAreaFieldFF.e2e.stories.js +23 -0
  67. package/src/TextAreaFieldFF/TextAreaFieldFF.js +57 -0
  68. package/src/TextAreaFieldFF/TextAreaFieldFF.prod.stories.js +111 -0
  69. package/src/TextAreaFieldFF/features/can_set_a_value/index.js +14 -0
  70. package/src/TextAreaFieldFF/features/can_set_a_value.feature +6 -0
  71. package/src/TextAreaFieldFF/features/displays_error/index.js +15 -0
  72. package/src/TextAreaFieldFF/features/displays_error.feature +6 -0
  73. package/src/__tests__/__snapshots__/index.test.js.snap +65 -0
  74. package/src/__tests__/index.test.js +37 -0
  75. package/src/formDecorator.js +80 -0
  76. package/src/index.js +28 -0
  77. package/src/locales/ar/translations.json +30 -0
  78. package/src/locales/ar_IQ/translations.json +30 -0
  79. package/src/locales/ckb/translations.json +30 -0
  80. package/src/locales/cs/translations.json +30 -0
  81. package/src/locales/da/translations.json +30 -0
  82. package/src/locales/en/translations.json +30 -0
  83. package/src/locales/es/translations.json +30 -0
  84. package/src/locales/es_419/translations.json +30 -0
  85. package/src/locales/fr/translations.json +30 -0
  86. package/src/locales/hi_IN/translations.json +30 -0
  87. package/src/locales/id/translations.json +30 -0
  88. package/src/locales/index.js +84 -0
  89. package/src/locales/km/translations.json +30 -0
  90. package/src/locales/ko_KR/translations.json +30 -0
  91. package/src/locales/lo/translations.json +30 -0
  92. package/src/locales/my/translations.json +30 -0
  93. package/src/locales/nb/translations.json +30 -0
  94. package/src/locales/nl/translations.json +30 -0
  95. package/src/locales/prs/translations.json +30 -0
  96. package/src/locales/ps/translations.json +30 -0
  97. package/src/locales/pt/translations.json +30 -0
  98. package/src/locales/pt_BR/translations.json +30 -0
  99. package/src/locales/ro/translations.json +30 -0
  100. package/src/locales/ru/translations.json +30 -0
  101. package/src/locales/si/translations.json +30 -0
  102. package/src/locales/sv/translations.json +30 -0
  103. package/src/locales/tet/translations.json +30 -0
  104. package/src/locales/tg/translations.json +30 -0
  105. package/src/locales/uk/translations.json +30 -0
  106. package/src/locales/ur/translations.json +30 -0
  107. package/src/locales/uz_Latn/translations.json +30 -0
  108. package/src/locales/uz_UZ_Cyrl/translations.json +30 -0
  109. package/src/locales/uz_UZ_Latn/translations.json +30 -0
  110. package/src/locales/vi/translations.json +30 -0
  111. package/src/locales/zh/translations.json +30 -0
  112. package/src/locales/zh_CN/translations.json +30 -0
  113. package/src/shared/helpers/createBlurHandler.js +9 -0
  114. package/src/shared/helpers/createChangeHandler.js +21 -0
  115. package/src/shared/helpers/createFocusHandler.js +9 -0
  116. package/src/shared/helpers/createSelectChangeHandler.js +6 -0
  117. package/src/shared/helpers/createToggleChangeHandler.js +9 -0
  118. package/src/shared/helpers/getValidationText.js +21 -0
  119. package/src/shared/helpers/hasError.js +3 -0
  120. package/src/shared/helpers/isLoading.js +4 -0
  121. package/src/shared/helpers/isValid.js +4 -0
  122. package/src/shared/helpers.js +9 -0
  123. package/src/shared/propTypes.js +48 -0
  124. package/src/transformers/arrayWithIdObjects.js +8 -0
  125. package/src/transformers/index.js +1 -0
  126. package/src/validators/__tests__/alphaNumeric.test.js +29 -0
  127. package/src/validators/__tests__/boolean.test.js +23 -0
  128. package/src/validators/__tests__/composeValidators.test.js +23 -0
  129. package/src/validators/__tests__/createCharacterLengthRange.test.js +59 -0
  130. package/src/validators/__tests__/createEqualTo.test.js +43 -0
  131. package/src/validators/__tests__/createMaxCharacterLength.test.js +24 -0
  132. package/src/validators/__tests__/createMaxNumber.test.js +21 -0
  133. package/src/validators/__tests__/createMinCharacterLength.test.js +24 -0
  134. package/src/validators/__tests__/createMinNumber.test.js +21 -0
  135. package/src/validators/__tests__/createNumberRange.test.js +68 -0
  136. package/src/validators/__tests__/createPattern.test.js +40 -0
  137. package/src/validators/__tests__/dhis2Password.test.js +51 -0
  138. package/src/validators/__tests__/dhis2Username.test.js +75 -0
  139. package/src/validators/__tests__/email.test.js +83 -0
  140. package/src/validators/__tests__/hasValue.test.js +21 -0
  141. package/src/validators/__tests__/integer.test.js +48 -0
  142. package/src/validators/__tests__/internationalPhoneNumber.test.js +49 -0
  143. package/src/validators/__tests__/number.test.js +39 -0
  144. package/src/validators/__tests__/string.test.js +29 -0
  145. package/src/validators/__tests__/url.test.js +106 -0
  146. package/src/validators/alphaNumeric.js +15 -0
  147. package/src/validators/boolean.js +11 -0
  148. package/src/validators/composeValidators.js +8 -0
  149. package/src/validators/createCharacterLengthRange.js +27 -0
  150. package/src/validators/createEqualTo.js +16 -0
  151. package/src/validators/createMaxCharacterLength.js +13 -0
  152. package/src/validators/createMaxNumber.js +13 -0
  153. package/src/validators/createMinCharacterLength.js +13 -0
  154. package/src/validators/createMinNumber.js +13 -0
  155. package/src/validators/createNumberRange.js +28 -0
  156. package/src/validators/createPattern.js +22 -0
  157. package/src/validators/dhis2Password.js +81 -0
  158. package/src/validators/dhis2Username.js +16 -0
  159. package/src/validators/email.js +38 -0
  160. package/src/validators/hasValue.js +8 -0
  161. package/src/validators/helpers/index.js +23 -0
  162. package/src/validators/index.js +20 -0
  163. package/src/validators/integer.js +20 -0
  164. package/src/validators/internationalPhoneNumber.js +56 -0
  165. package/src/validators/number.js +9 -0
  166. package/src/validators/string.js +9 -0
  167. package/src/validators/test-helpers/index.js +21 -0
  168. package/src/validators/url.js +15 -0
@@ -0,0 +1,30 @@
1
+ {
2
+ "Upload file": "",
3
+ "Upload files": "",
4
+ "Remove": "移除",
5
+ "Please provide an alpha-numeric value": "",
6
+ "Please provide a boolean value": "",
7
+ "Please enter between {{lowerBound}} and {{upperBound}} characters": "",
8
+ "Please make sure the value of this input matches the value in \"{{otherField}}\".": "请确保此输入的值与“ {{otherField}}”中的值匹配。",
9
+ "Please enter a maximum of {{upperBound}} characters": "",
10
+ "Please enter a number with a maximum of {{upperBound}}": "",
11
+ "Please enter at least {{lowerBound}} characters": "",
12
+ "Please enter a number of at least {{lowerBound}}": "",
13
+ "Number cannot be less than {{lowerBound}} or more than {{upperBound}}": "",
14
+ "Please make sure the value of this input matches the pattern {{patternString}}.": "",
15
+ "Password should be a string": "",
16
+ "Password should be at least 8 characters long": "口令至少8个字符",
17
+ "Password should be no longer than 34 characters": "口令不能超过34字符",
18
+ "Password should contain at least one lowercase letter": "口令至少包括应该小写字母",
19
+ "Password should contain at least one UPPERCASE letter": "口令至少包括一个大写字母",
20
+ "Password should contain at least one number": "口令至少包括应该数字",
21
+ "Password should have at least one special character": "口令至少包括一个特殊字符",
22
+ "Please provide a username between 4 and 255 characters": "",
23
+ "Please provide a valid email address": "有效的邮箱",
24
+ "Please provide a value": "",
25
+ "Please provide a round number without decimals": "",
26
+ "Please provide a valid international phone number.": "",
27
+ "Please provide a number": "",
28
+ "Please provide a string": "",
29
+ "Please provide a valid url": "有效的URL"
30
+ }
@@ -0,0 +1,9 @@
1
+ const createBlurHandler = (input, onBlur) => (payload, event) => {
2
+ input.onBlur(event)
3
+
4
+ if (onBlur && typeof onBlur === 'function') {
5
+ onBlur(payload, event)
6
+ }
7
+ }
8
+
9
+ export { createBlurHandler }
@@ -0,0 +1,21 @@
1
+ const PRIMITIVE_TYPES = new Set(['string', 'number', 'boolean'])
2
+
3
+ const createChangeHandler =
4
+ ({ onChange }) =>
5
+ (payload) => {
6
+ if (payload && 'value' in payload) {
7
+ // ui event signature
8
+ onChange(payload.value)
9
+ } else if (payload && payload.target && 'value' in payload.target) {
10
+ // synthetic event
11
+ onChange(payload.target.value)
12
+ } else if (PRIMITIVE_TYPES.has(typeof payload)) {
13
+ // directly usable value
14
+ onChange(payload)
15
+ } else {
16
+ // ¯\_(ツ)_/¯
17
+ throw new Error('Could not process event payload')
18
+ }
19
+ }
20
+
21
+ export { createChangeHandler }
@@ -0,0 +1,9 @@
1
+ const createFocusHandler = (input, onFocus) => (payload, event) => {
2
+ input.onFocus(event)
3
+
4
+ if (onFocus && typeof onFocus === 'function') {
5
+ onFocus(payload, event)
6
+ }
7
+ }
8
+
9
+ export { createFocusHandler }
@@ -0,0 +1,6 @@
1
+ const createSelectChangeHandler =
2
+ ({ onChange }) =>
3
+ ({ selected }) => {
4
+ onChange(selected)
5
+ }
6
+ export { createSelectChangeHandler }
@@ -0,0 +1,9 @@
1
+ const createToggleChangeHandler = (input, onChange) => (payload, event) => {
2
+ input.onChange(event)
3
+
4
+ if (onChange && typeof onChange === 'function') {
5
+ onChange(payload, event)
6
+ }
7
+ }
8
+
9
+ export { createToggleChangeHandler }
@@ -0,0 +1,21 @@
1
+ import { hasError } from './hasError.js'
2
+
3
+ const getValidationText = (meta, validationText, error) => {
4
+ if (validationText) {
5
+ return validationText
6
+ }
7
+
8
+ if (hasError(meta, error)) {
9
+ if (meta.error) {
10
+ return meta.error
11
+ }
12
+
13
+ if (meta.submitError) {
14
+ return meta.submitError
15
+ }
16
+ }
17
+
18
+ return ''
19
+ }
20
+
21
+ export { getValidationText }
@@ -0,0 +1,3 @@
1
+ const hasError = (meta, error) => error || (meta.touched && meta.invalid)
2
+
3
+ export { hasError }
@@ -0,0 +1,4 @@
1
+ const isLoading = (meta, loading, showLoadingStatus) =>
2
+ loading || (showLoadingStatus && meta.validating)
3
+
4
+ export { isLoading }
@@ -0,0 +1,4 @@
1
+ const isValid = (meta, valid, showValidStatus) =>
2
+ valid || (showValidStatus && meta.touched && meta.valid)
3
+
4
+ export { isValid }
@@ -0,0 +1,9 @@
1
+ export { createBlurHandler } from './helpers/createBlurHandler.js'
2
+ export { createChangeHandler } from './helpers/createChangeHandler.js'
3
+ export { createFocusHandler } from './helpers/createFocusHandler.js'
4
+ export { createSelectChangeHandler } from './helpers/createSelectChangeHandler.js'
5
+ export { createToggleChangeHandler } from './helpers/createToggleChangeHandler.js'
6
+ export { getValidationText } from './helpers/getValidationText.js'
7
+ export { hasError } from './helpers/hasError.js'
8
+ export { isLoading } from './helpers/isLoading.js'
9
+ export { isValid } from './helpers/isValid.js'
@@ -0,0 +1,48 @@
1
+ import PropTypes from 'prop-types'
2
+
3
+ const toggleGroupOptionsProp = PropTypes.arrayOf(
4
+ PropTypes.shape({
5
+ label: PropTypes.string.isRequired,
6
+ value: PropTypes.string.isRequired,
7
+ })
8
+ )
9
+
10
+ const inputPropType = PropTypes.shape({
11
+ name: PropTypes.string.isRequired,
12
+ onChange: PropTypes.func.isRequired,
13
+ value: PropTypes.any,
14
+ onBlur: PropTypes.func,
15
+ onFocus: PropTypes.func,
16
+ })
17
+ const inputArgType = {
18
+ table: {
19
+ type: {
20
+ summary:
21
+ '{ name: string (required), onChange: func (required), value: any, onBlur: func, onFocus: func }',
22
+ },
23
+ },
24
+ }
25
+
26
+ const metaPropType = PropTypes.shape({
27
+ error: PropTypes.string,
28
+ invalid: PropTypes.bool,
29
+ touched: PropTypes.bool,
30
+ valid: PropTypes.bool,
31
+ validating: PropTypes.bool,
32
+ })
33
+ const metaArgType = {
34
+ table: {
35
+ type: {
36
+ summary:
37
+ '{ error: string, invalid: bool, touched: bool, valid: bool, validating: bool }',
38
+ },
39
+ },
40
+ }
41
+
42
+ export {
43
+ toggleGroupOptionsProp,
44
+ inputPropType,
45
+ inputArgType,
46
+ metaPropType,
47
+ metaArgType,
48
+ }
@@ -0,0 +1,8 @@
1
+ const format = (value) => (!value ? [] : value.map(({ id }) => id))
2
+
3
+ const parse = (value) =>
4
+ !value || (Array.isArray(value) && value.length === 0)
5
+ ? undefined
6
+ : value.map((id) => ({ id }))
7
+
8
+ export const arrayWithIdObjects = { format, parse }
@@ -0,0 +1 @@
1
+ export { arrayWithIdObjects } from './arrayWithIdObjects.js'
@@ -0,0 +1,29 @@
1
+ import { alphaNumeric, invalidAlphaNumericMessage } from '../alphaNumeric.js'
2
+ import {
3
+ testValidatorValues,
4
+ allowsEmptyValues,
5
+ } from '../test-helpers/index.js'
6
+
7
+ describe('validator: alphaNumeric', () => {
8
+ allowsEmptyValues(alphaNumeric)
9
+
10
+ describe('allows alpha-numeric values', () => {
11
+ testValidatorValues(alphaNumeric, undefined, [
12
+ '123456',
13
+ 'abcdef',
14
+ 'a1b2c3',
15
+ 'A1B2C3d4e5',
16
+ 'I have spaces',
17
+ ])
18
+ })
19
+
20
+ describe('rejects non-alpha-numeric values', () => {
21
+ testValidatorValues(alphaNumeric, invalidAlphaNumericMessage, [
22
+ '.,/|~',
23
+ true,
24
+ false,
25
+ 0,
26
+ 1,
27
+ ])
28
+ })
29
+ })
@@ -0,0 +1,23 @@
1
+ import { boolean, invalidBooleanMessage } from '../boolean.js'
2
+ import {
3
+ testValidatorValues,
4
+ allowsEmptyValues,
5
+ } from '../test-helpers/index.js'
6
+
7
+ describe('validator: boolean', () => {
8
+ allowsEmptyValues(boolean)
9
+
10
+ describe('allows boolean values', () => {
11
+ testValidatorValues(boolean, undefined, [true, false])
12
+ })
13
+
14
+ describe('rejects non-boolean values', () => {
15
+ testValidatorValues(boolean, invalidBooleanMessage, [
16
+ 'text',
17
+ 3,
18
+ {},
19
+ [],
20
+ () => {},
21
+ ])
22
+ })
23
+ })
@@ -0,0 +1,23 @@
1
+ import { composeValidators } from '../composeValidators.js'
2
+ import { email, invalidEmailMessage } from '../email.js'
3
+ import { hasValue, hasValueMessage } from '../hasValue.js'
4
+
5
+ describe('composeValidators', () => {
6
+ const validator = composeValidators(hasValue, email)
7
+
8
+ it('should return undefined for valid values', () => {
9
+ expect(validator('test@dhis2.org')).toBe(undefined)
10
+ })
11
+
12
+ it('should return the required message for empty values', () => {
13
+ const validator = composeValidators(hasValue, email)
14
+
15
+ expect(validator('')).toBe(hasValueMessage)
16
+ })
17
+
18
+ it('should return invalid e-mail message for malformed strings', () => {
19
+ const validator = composeValidators(hasValue, email)
20
+
21
+ expect(validator('test@dhis2.')).toBe(invalidEmailMessage)
22
+ })
23
+ })
@@ -0,0 +1,59 @@
1
+ import { createCharacterLengthRange } from '../createCharacterLengthRange.js'
2
+ import { requiredArgumentErrorMessage } from '../helpers/index.js'
3
+ import {
4
+ testValidatorValues,
5
+ allowsEmptyValues,
6
+ } from '../test-helpers/index.js'
7
+
8
+ describe('validator: createCharacterLengthRange', () => {
9
+ const betweenSixAndTenChars = createCharacterLengthRange(6, 10)
10
+ const inValidMsg = 'Please enter between 6 and 10 characters'
11
+
12
+ it('should throw an error when lower or upper bound are not a number', () => {
13
+ expect(() => {
14
+ createCharacterLengthRange(undefined, undefined)
15
+ }).toThrowError(requiredArgumentErrorMessage)
16
+ expect(() => {
17
+ createCharacterLengthRange('test', 'test')
18
+ }).toThrowError(requiredArgumentErrorMessage)
19
+ expect(() => {
20
+ createCharacterLengthRange(1, undefined)
21
+ }).toThrowError(requiredArgumentErrorMessage)
22
+ expect(() => {
23
+ createCharacterLengthRange(undefined, 0)
24
+ }).toThrowError(requiredArgumentErrorMessage)
25
+ })
26
+
27
+ it('should create a function', () => {
28
+ expect(typeof betweenSixAndTenChars).toEqual('function')
29
+ })
30
+
31
+ allowsEmptyValues(betweenSixAndTenChars)
32
+
33
+ describe('allows within-range strings', () => {
34
+ testValidatorValues(betweenSixAndTenChars, undefined, [
35
+ 'abcdef', // 6
36
+ 'abcdefgh',
37
+ 'abcdefghij', // 10
38
+ ])
39
+ })
40
+
41
+ describe('rejects non-string values', () => {
42
+ testValidatorValues(betweenSixAndTenChars, inValidMsg, [
43
+ true,
44
+ 3,
45
+ {},
46
+ [],
47
+ () => {},
48
+ ])
49
+ })
50
+
51
+ describe('rejects out-of-range strings', () => {
52
+ testValidatorValues(betweenSixAndTenChars, inValidMsg, [
53
+ 'a',
54
+ 'abcde', // 5
55
+ 'abcdefghijk', // 11
56
+ 'abcdefghijklmnopqrstuvw',
57
+ ])
58
+ })
59
+ })
@@ -0,0 +1,43 @@
1
+ import { createEqualTo } from '../createEqualTo.js'
2
+ import { requiredArgumentErrorMessage } from '../helpers/index.js'
3
+ import { allowsEmptyValues } from '../test-helpers/index.js'
4
+
5
+ describe('validator: createEqualTo', () => {
6
+ const equalToFoo = createEqualTo('foo')
7
+
8
+ it('should throw an error when key is not a string', () => {
9
+ expect(() => {
10
+ createEqualTo(undefined)
11
+ }).toThrowError(requiredArgumentErrorMessage)
12
+ expect(() => {
13
+ createEqualTo({})
14
+ }).toThrowError(requiredArgumentErrorMessage)
15
+ })
16
+
17
+ it('should create a function', () => {
18
+ expect(typeof equalToFoo).toEqual('function')
19
+ })
20
+
21
+ allowsEmptyValues(equalToFoo)
22
+
23
+ it('should return undefined when the fields have equal values', () => {
24
+ const sameValue = 'abcde'
25
+
26
+ expect(equalToFoo(sameValue, { foo: sameValue })).toEqual(undefined)
27
+ })
28
+
29
+ it('should return an error string when the fields have inequal values', () => {
30
+ const inValidFooMsg =
31
+ 'Please make sure the value of this input matches the value in "foo".'
32
+
33
+ expect(equalToFoo('this', { foo: 'that' })).toEqual(inValidFooMsg)
34
+ })
35
+
36
+ it('should use the property description in the error string if provided', () => {
37
+ const equalToBar = createEqualTo('bar', 'Barista')
38
+ const inValidBarMsg =
39
+ 'Please make sure the value of this input matches the value in "Barista".'
40
+
41
+ expect(equalToBar('this', { bar: 'that' })).toEqual(inValidBarMsg)
42
+ })
43
+ })
@@ -0,0 +1,24 @@
1
+ import { createMaxCharacterLength } from '../createMaxCharacterLength.js'
2
+ import { testValidatorValues } from '../test-helpers/index.js'
3
+
4
+ describe('validator: createMaxCharacterLength', () => {
5
+ const maxSixChars = createMaxCharacterLength(6)
6
+ const errorMessage = 'Please enter a maximum of 6 characters'
7
+
8
+ /*
9
+ * Since createMaxCharacterLength calls createNumberRange internally
10
+ * a lot of things have been tested there and here we focus
11
+ * purely on the bounderies
12
+ */
13
+
14
+ describe('allows strings with a lower or equal length than the upper bound', () => {
15
+ testValidatorValues(maxSixChars, undefined, ['a', '123456'])
16
+ })
17
+
18
+ describe('rejects strings a length above the upper bound', () => {
19
+ testValidatorValues(maxSixChars, errorMessage, [
20
+ '1234567',
21
+ 'some even longer text here....',
22
+ ])
23
+ })
24
+ })
@@ -0,0 +1,21 @@
1
+ import { createMaxNumber } from '../createMaxNumber.js'
2
+ import { testValidatorValues } from '../test-helpers/index.js'
3
+
4
+ describe('validator: createMaxNumber', () => {
5
+ const maxSix = createMaxNumber(6)
6
+ const errorMessage = 'Please enter a number with a maximum of 6'
7
+
8
+ /*
9
+ * Since createMaxNumber calls createNumberRange internally
10
+ * a lot of things have been tested there and here we focus
11
+ * purely on the bounderies
12
+ */
13
+
14
+ describe('allows numbers up to and including the upper bound', () => {
15
+ testValidatorValues(maxSix, undefined, [-1000, 0, 1, 6])
16
+ })
17
+
18
+ describe('rejects numbers above the upper bound', () => {
19
+ testValidatorValues(maxSix, errorMessage, [6.000001, 7, 100000])
20
+ })
21
+ })
@@ -0,0 +1,24 @@
1
+ import { createMinCharacterLength } from '../createMinCharacterLength.js'
2
+ import { testValidatorValues } from '../test-helpers/index.js'
3
+
4
+ describe('validator: createMinCharacterLength', () => {
5
+ const atLeastSixChars = createMinCharacterLength(6)
6
+ const errorMessage = 'Please enter at least 6 characters'
7
+
8
+ /*
9
+ * Since createMinCharacterLength calls createCharacterLengthRange internally
10
+ * a lot of things have been tested there and here we focus
11
+ * purely on the bounderies
12
+ */
13
+
14
+ describe('allows strings with an equal or greater length than the lower bound', () => {
15
+ testValidatorValues(atLeastSixChars, undefined, [
16
+ '123456',
17
+ 'an even longer string',
18
+ ])
19
+ })
20
+
21
+ describe('rejects strings a length below the lower bound', () => {
22
+ testValidatorValues(atLeastSixChars, errorMessage, ['a', '12345'])
23
+ })
24
+ })
@@ -0,0 +1,21 @@
1
+ import { createMinNumber } from '../createMinNumber.js'
2
+ import { testValidatorValues } from '../test-helpers/index.js'
3
+
4
+ describe('validator: createMinNumber', () => {
5
+ const atLeastSix = createMinNumber(6)
6
+ const errorMessage = 'Please enter a number of at least 6'
7
+
8
+ /*
9
+ * Since createMinNumber calls createNumberRange internally
10
+ * a lot of things have been tested there and here we focus
11
+ * purely on the bounderies
12
+ */
13
+
14
+ describe('allows numbers equal to or greater than the lower bound', () => {
15
+ testValidatorValues(atLeastSix, undefined, [6, 6.00001, 1000000])
16
+ })
17
+
18
+ describe('rejects numbers below the lower bound', () => {
19
+ testValidatorValues(atLeastSix, errorMessage, [-10000, 0, 1, 5.999999])
20
+ })
21
+ })
@@ -0,0 +1,68 @@
1
+ import { createNumberRange } from '../createNumberRange.js'
2
+ import { requiredArgumentErrorMessage } from '../helpers/index.js'
3
+ import {
4
+ testValidatorValues,
5
+ allowsEmptyValues,
6
+ } from '../test-helpers/index.js'
7
+
8
+ describe('validator: createNumberRange', () => {
9
+ const betweenSixAndTen = createNumberRange(6, 10)
10
+ const errorMessage = 'Number cannot be less than 6 or more than 10'
11
+
12
+ it('should throw an error when lower or upper bound are not a number', () => {
13
+ expect(() => {
14
+ createNumberRange(undefined, undefined)
15
+ }).toThrowError(requiredArgumentErrorMessage)
16
+ expect(() => {
17
+ createNumberRange('test', 'test')
18
+ }).toThrowError(requiredArgumentErrorMessage)
19
+ expect(() => {
20
+ createNumberRange(1, undefined)
21
+ }).toThrowError(requiredArgumentErrorMessage)
22
+ expect(() => {
23
+ createNumberRange(undefined, 0)
24
+ }).toThrowError(requiredArgumentErrorMessage)
25
+ })
26
+
27
+ it('should create a function', () => {
28
+ expect(typeof betweenSixAndTen).toEqual('function')
29
+ })
30
+
31
+ allowsEmptyValues(betweenSixAndTen)
32
+
33
+ describe('allows floats, integers and string representations of numbers', () => {
34
+ testValidatorValues(betweenSixAndTen, undefined, [
35
+ 7,
36
+ 7.1,
37
+ 0.71e1,
38
+ '7',
39
+ '7.1',
40
+ ])
41
+ })
42
+
43
+ describe('allows within-range numbers', () => {
44
+ testValidatorValues(
45
+ betweenSixAndTen,
46
+ undefined,
47
+ [6, 8, 10, 9.999999, 6.000001]
48
+ )
49
+ })
50
+
51
+ describe('rejects non-numerical values', () => {
52
+ testValidatorValues(betweenSixAndTen, errorMessage, [
53
+ 'test',
54
+ true,
55
+ {},
56
+ [],
57
+ () => {},
58
+ ])
59
+ })
60
+
61
+ describe('rejects out-of-range numbers', () => {
62
+ testValidatorValues(
63
+ betweenSixAndTen,
64
+ errorMessage,
65
+ [3, 5, 5.999999, 10.000001, 1000000]
66
+ )
67
+ })
68
+ })
@@ -0,0 +1,40 @@
1
+ import { createPattern, invalidPatternMessage } from '../createPattern.js'
2
+ import { allowsEmptyValues } from '../test-helpers/index.js'
3
+
4
+ describe('validator: createPattern', () => {
5
+ const pattern = /^test$/
6
+ const equalToTestPattern = createPattern(pattern)
7
+
8
+ it('should throw an error when pattern is not a regex object', () => {
9
+ expect(() => {
10
+ createPattern(undefined)
11
+ }).toThrowError(invalidPatternMessage)
12
+ expect(() => {
13
+ createPattern('test')
14
+ }).toThrowError(invalidPatternMessage)
15
+ })
16
+
17
+ it('should create a function', () => {
18
+ expect(typeof equalToTestPattern).toEqual('function')
19
+ })
20
+
21
+ allowsEmptyValues(equalToTestPattern)
22
+
23
+ it('should return undefined when the input matches the pattern', () => {
24
+ expect(equalToTestPattern('test')).toEqual(undefined)
25
+ })
26
+
27
+ it('should return an error string when input does not match the pattern', () => {
28
+ const escapedRegexString = '/^test$/'
29
+ const invalidMsg = `Please make sure the value of this input matches the pattern ${escapedRegexString}.`
30
+
31
+ expect(equalToTestPattern('bad input')).toEqual(invalidMsg)
32
+ })
33
+
34
+ it('should return an custon error string when one was provided and input does not match the pattern', () => {
35
+ const invalidMsg = 'You should not have done this'
36
+ const withCustomMessage = createPattern(pattern, invalidMsg)
37
+
38
+ expect(withCustomMessage('bad input')).toEqual(invalidMsg)
39
+ })
40
+ })
@@ -0,0 +1,51 @@
1
+ import { dhis2Password, errorMessages } from '../dhis2Password.js'
2
+ import {
3
+ testValidatorValues,
4
+ allowsEmptyValues,
5
+ } from '../test-helpers/index.js'
6
+
7
+ describe('validator: dhis2Password', () => {
8
+ allowsEmptyValues(dhis2Password)
9
+
10
+ it('should return undefined for a valid password', () => {
11
+ expect(dhis2Password('Testing123!')).toEqual(undefined)
12
+ })
13
+
14
+ describe('rejects value types other than string', () => {
15
+ testValidatorValues(dhis2Password, errorMessages.notString, [
16
+ true,
17
+ 3,
18
+ {},
19
+ [],
20
+ () => {},
21
+ ])
22
+ })
23
+
24
+ it('should return the "password too short" message if password is less than 8 characters', () => {
25
+ expect(dhis2Password('123')).toEqual(errorMessages.tooShort)
26
+ })
27
+
28
+ it('should return the "password too long" message if password is more than 34 characters', () => {
29
+ expect(
30
+ dhis2Password('abcdefghijklmnopqrstuvwxyz12345678910111213')
31
+ ).toEqual(errorMessages.tooLong)
32
+ })
33
+
34
+ it('should return the "no lowercase" message if password does not contain lower case characters', () => {
35
+ expect(dhis2Password('TESTING123!')).toEqual(errorMessages.noLowerCase)
36
+ })
37
+
38
+ it('should return the "no uppercase" message if password has no uppercase characters', () => {
39
+ expect(dhis2Password('testing123!')).toEqual(errorMessages.noUpperCase)
40
+ })
41
+
42
+ it('should return the "no number" message if password has no digits', () => {
43
+ expect(dhis2Password('Testing!')).toEqual(errorMessages.noNumber)
44
+ })
45
+
46
+ it('should return the "no special character" message if password has no special characters', () => {
47
+ expect(dhis2Password('Testing123')).toEqual(
48
+ errorMessages.noSpecialCharacter
49
+ )
50
+ })
51
+ })