@hookform/resolvers 2.8.1

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 (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +420 -0
  3. package/class-validator/dist/class-validator.d.ts +2 -0
  4. package/class-validator/dist/class-validator.js +2 -0
  5. package/class-validator/dist/class-validator.js.map +1 -0
  6. package/class-validator/dist/class-validator.mjs +2 -0
  7. package/class-validator/dist/class-validator.modern.js +2 -0
  8. package/class-validator/dist/class-validator.modern.js.map +1 -0
  9. package/class-validator/dist/class-validator.module.js +2 -0
  10. package/class-validator/dist/class-validator.module.js.map +1 -0
  11. package/class-validator/dist/class-validator.umd.js +2 -0
  12. package/class-validator/dist/class-validator.umd.js.map +1 -0
  13. package/class-validator/dist/index.d.ts +2 -0
  14. package/class-validator/dist/types.d.ts +8 -0
  15. package/class-validator/package.json +19 -0
  16. package/class-validator/src/__tests__/Form-native-validation.tsx +83 -0
  17. package/class-validator/src/__tests__/Form.tsx +55 -0
  18. package/class-validator/src/__tests__/__fixtures__/data.ts +88 -0
  19. package/class-validator/src/__tests__/__snapshots__/class-validator.ts.snap +207 -0
  20. package/class-validator/src/__tests__/class-validator.ts +87 -0
  21. package/class-validator/src/class-validator.ts +62 -0
  22. package/class-validator/src/index.ts +2 -0
  23. package/class-validator/src/types.ts +22 -0
  24. package/computed-types/dist/computed-types.d.ts +2 -0
  25. package/computed-types/dist/computed-types.js +2 -0
  26. package/computed-types/dist/computed-types.js.map +1 -0
  27. package/computed-types/dist/computed-types.mjs +2 -0
  28. package/computed-types/dist/computed-types.modern.js +2 -0
  29. package/computed-types/dist/computed-types.modern.js.map +1 -0
  30. package/computed-types/dist/computed-types.module.js +2 -0
  31. package/computed-types/dist/computed-types.module.js.map +1 -0
  32. package/computed-types/dist/computed-types.umd.js +2 -0
  33. package/computed-types/dist/computed-types.umd.js.map +1 -0
  34. package/computed-types/dist/index.d.ts +2 -0
  35. package/computed-types/dist/types.d.ts +2 -0
  36. package/computed-types/package.json +17 -0
  37. package/computed-types/src/__tests__/Form-native-validation.tsx +85 -0
  38. package/computed-types/src/__tests__/Form.tsx +54 -0
  39. package/computed-types/src/__tests__/__fixtures__/data.ts +72 -0
  40. package/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +55 -0
  41. package/computed-types/src/__tests__/computed-types.ts +24 -0
  42. package/computed-types/src/computed-types.ts +43 -0
  43. package/computed-types/src/index.ts +2 -0
  44. package/computed-types/src/types.ts +14 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/resolvers.js +2 -0
  47. package/dist/resolvers.js.map +1 -0
  48. package/dist/resolvers.mjs +2 -0
  49. package/dist/resolvers.mjs.map +1 -0
  50. package/dist/resolvers.module.js +2 -0
  51. package/dist/resolvers.module.js.map +1 -0
  52. package/dist/resolvers.umd.js +2 -0
  53. package/dist/resolvers.umd.js.map +1 -0
  54. package/dist/toNestError.d.ts +2 -0
  55. package/dist/validateFieldsNatively.d.ts +2 -0
  56. package/io-ts/dist/arrayToPath.d.ts +3 -0
  57. package/io-ts/dist/errorsToRecord.d.ts +5 -0
  58. package/io-ts/dist/index.d.ts +2 -0
  59. package/io-ts/dist/io-ts.d.ts +2 -0
  60. package/io-ts/dist/io-ts.js +2 -0
  61. package/io-ts/dist/io-ts.js.map +1 -0
  62. package/io-ts/dist/io-ts.mjs +2 -0
  63. package/io-ts/dist/io-ts.modern.js +2 -0
  64. package/io-ts/dist/io-ts.modern.js.map +1 -0
  65. package/io-ts/dist/io-ts.module.js +2 -0
  66. package/io-ts/dist/io-ts.module.js.map +1 -0
  67. package/io-ts/dist/io-ts.umd.js +2 -0
  68. package/io-ts/dist/io-ts.umd.js.map +1 -0
  69. package/io-ts/dist/types.d.ts +7 -0
  70. package/io-ts/package.json +19 -0
  71. package/io-ts/src/__tests__/Form-native-validation.tsx +89 -0
  72. package/io-ts/src/__tests__/Form.tsx +65 -0
  73. package/io-ts/src/__tests__/__fixtures__/data.ts +129 -0
  74. package/io-ts/src/__tests__/__snapshots__/io-ts.ts.snap +89 -0
  75. package/io-ts/src/__tests__/io-ts.ts +37 -0
  76. package/io-ts/src/arrayToPath.ts +18 -0
  77. package/io-ts/src/errorsToRecord.ts +131 -0
  78. package/io-ts/src/index.ts +2 -0
  79. package/io-ts/src/io-ts.ts +33 -0
  80. package/io-ts/src/types.ts +23 -0
  81. package/joi/dist/index.d.ts +2 -0
  82. package/joi/dist/joi.d.ts +2 -0
  83. package/joi/dist/joi.js +2 -0
  84. package/joi/dist/joi.js.map +1 -0
  85. package/joi/dist/joi.mjs +2 -0
  86. package/joi/dist/joi.modern.js +2 -0
  87. package/joi/dist/joi.modern.js.map +1 -0
  88. package/joi/dist/joi.module.js +2 -0
  89. package/joi/dist/joi.module.js.map +1 -0
  90. package/joi/dist/joi.umd.js +2 -0
  91. package/joi/dist/joi.umd.js.map +1 -0
  92. package/joi/dist/types.d.ts +5 -0
  93. package/joi/package.json +17 -0
  94. package/joi/src/__tests__/Form-native-validation.tsx +89 -0
  95. package/joi/src/__tests__/Form.tsx +61 -0
  96. package/joi/src/__tests__/__fixtures__/data.ts +85 -0
  97. package/joi/src/__tests__/__snapshots__/joi.ts.snap +293 -0
  98. package/joi/src/__tests__/joi.ts +98 -0
  99. package/joi/src/index.ts +2 -0
  100. package/joi/src/joi.ts +81 -0
  101. package/joi/src/types.ts +16 -0
  102. package/nope/dist/index.d.ts +2 -0
  103. package/nope/dist/nope.d.ts +2 -0
  104. package/nope/dist/nope.js +2 -0
  105. package/nope/dist/nope.js.map +1 -0
  106. package/nope/dist/nope.mjs +2 -0
  107. package/nope/dist/nope.modern.js +2 -0
  108. package/nope/dist/nope.modern.js.map +1 -0
  109. package/nope/dist/nope.module.js +2 -0
  110. package/nope/dist/nope.module.js.map +1 -0
  111. package/nope/dist/nope.umd.js +2 -0
  112. package/nope/dist/nope.umd.js.map +1 -0
  113. package/nope/dist/types.d.ts +6 -0
  114. package/nope/package.json +18 -0
  115. package/nope/src/__tests__/Form-native-validation.tsx +89 -0
  116. package/nope/src/__tests__/Form.tsx +57 -0
  117. package/nope/src/__tests__/__fixtures__/data.ts +70 -0
  118. package/nope/src/__tests__/__snapshots__/nope.ts.snap +43 -0
  119. package/nope/src/__tests__/nope.ts +28 -0
  120. package/nope/src/index.ts +2 -0
  121. package/nope/src/nope.ts +46 -0
  122. package/nope/src/types.ts +22 -0
  123. package/package.json +216 -0
  124. package/superstruct/dist/index.d.ts +2 -0
  125. package/superstruct/dist/superstruct.d.ts +2 -0
  126. package/superstruct/dist/superstruct.js +2 -0
  127. package/superstruct/dist/superstruct.js.map +1 -0
  128. package/superstruct/dist/superstruct.mjs +2 -0
  129. package/superstruct/dist/superstruct.modern.js +2 -0
  130. package/superstruct/dist/superstruct.modern.js.map +1 -0
  131. package/superstruct/dist/superstruct.module.js +2 -0
  132. package/superstruct/dist/superstruct.module.js.map +1 -0
  133. package/superstruct/dist/superstruct.umd.js +2 -0
  134. package/superstruct/dist/superstruct.umd.js.map +1 -0
  135. package/superstruct/dist/types.d.ts +5 -0
  136. package/superstruct/package.json +18 -0
  137. package/superstruct/src/__tests__/Form-native-validation.tsx +86 -0
  138. package/superstruct/src/__tests__/Form.tsx +62 -0
  139. package/superstruct/src/__tests__/__fixtures__/data.ts +75 -0
  140. package/superstruct/src/__tests__/__snapshots__/superstruct.ts.snap +64 -0
  141. package/superstruct/src/__tests__/superstruct.ts +24 -0
  142. package/superstruct/src/index.ts +2 -0
  143. package/superstruct/src/superstruct.ts +37 -0
  144. package/superstruct/src/types.ts +17 -0
  145. package/typanion/dist/index.d.ts +2 -0
  146. package/typanion/dist/typanion.d.ts +2 -0
  147. package/typanion/dist/typanion.js +2 -0
  148. package/typanion/dist/typanion.js.map +1 -0
  149. package/typanion/dist/typanion.mjs +2 -0
  150. package/typanion/dist/typanion.modern.js +2 -0
  151. package/typanion/dist/typanion.modern.js.map +1 -0
  152. package/typanion/dist/typanion.module.js +2 -0
  153. package/typanion/dist/typanion.module.js.map +1 -0
  154. package/typanion/dist/typanion.umd.js +2 -0
  155. package/typanion/dist/typanion.umd.js.map +1 -0
  156. package/typanion/dist/types.d.ts +6 -0
  157. package/typanion/package.json +18 -0
  158. package/typanion/src/__tests__/Form-native-validation.tsx +89 -0
  159. package/typanion/src/__tests__/Form.tsx +61 -0
  160. package/typanion/src/__tests__/__fixtures__/data.ts +77 -0
  161. package/typanion/src/__tests__/__snapshots__/typanion.ts.snap +67 -0
  162. package/typanion/src/__tests__/typanion.ts +31 -0
  163. package/typanion/src/index.ts +2 -0
  164. package/typanion/src/typanion.ts +44 -0
  165. package/typanion/src/types.ts +28 -0
  166. package/vest/dist/index.d.ts +1 -0
  167. package/vest/dist/vest.d.ts +2 -0
  168. package/vest/dist/vest.js +2 -0
  169. package/vest/dist/vest.js.map +1 -0
  170. package/vest/dist/vest.mjs +2 -0
  171. package/vest/dist/vest.modern.js +2 -0
  172. package/vest/dist/vest.modern.js.map +1 -0
  173. package/vest/dist/vest.module.js +2 -0
  174. package/vest/dist/vest.module.js.map +1 -0
  175. package/vest/dist/vest.umd.js +2 -0
  176. package/vest/dist/vest.umd.js.map +1 -0
  177. package/vest/package.json +18 -0
  178. package/vest/src/__tests__/Form-native-validation.tsx +93 -0
  179. package/vest/src/__tests__/Form.tsx +64 -0
  180. package/vest/src/__tests__/__fixtures__/data.ts +67 -0
  181. package/vest/src/__tests__/__snapshots__/vest.ts.snap +141 -0
  182. package/vest/src/__tests__/vest.ts +71 -0
  183. package/vest/src/index.ts +1 -0
  184. package/vest/src/types.ts +20 -0
  185. package/vest/src/vest.ts +51 -0
  186. package/yup/dist/index.d.ts +2 -0
  187. package/yup/dist/types.d.ts +8 -0
  188. package/yup/dist/yup.d.ts +2 -0
  189. package/yup/dist/yup.js +2 -0
  190. package/yup/dist/yup.js.map +1 -0
  191. package/yup/dist/yup.mjs +2 -0
  192. package/yup/dist/yup.modern.js +2 -0
  193. package/yup/dist/yup.modern.js.map +1 -0
  194. package/yup/dist/yup.module.js +2 -0
  195. package/yup/dist/yup.module.js.map +1 -0
  196. package/yup/dist/yup.umd.js +2 -0
  197. package/yup/dist/yup.umd.js.map +1 -0
  198. package/yup/package.json +17 -0
  199. package/yup/src/__tests__/Form-native-validation.tsx +85 -0
  200. package/yup/src/__tests__/Form.tsx +54 -0
  201. package/yup/src/__tests__/__fixtures__/data.ts +72 -0
  202. package/yup/src/__tests__/__snapshots__/yup.ts.snap +231 -0
  203. package/yup/src/__tests__/yup.ts +174 -0
  204. package/yup/src/index.ts +2 -0
  205. package/yup/src/types.ts +21 -0
  206. package/yup/src/yup.ts +75 -0
  207. package/zod/dist/index.d.ts +2 -0
  208. package/zod/dist/types.d.ts +5 -0
  209. package/zod/dist/zod.d.ts +2 -0
  210. package/zod/dist/zod.js +2 -0
  211. package/zod/dist/zod.js.map +1 -0
  212. package/zod/dist/zod.mjs +2 -0
  213. package/zod/dist/zod.modern.js +2 -0
  214. package/zod/dist/zod.modern.js.map +1 -0
  215. package/zod/dist/zod.module.js +2 -0
  216. package/zod/dist/zod.module.js.map +1 -0
  217. package/zod/dist/zod.umd.js +2 -0
  218. package/zod/dist/zod.umd.js.map +1 -0
  219. package/zod/package.json +17 -0
  220. package/zod/src/__tests__/Form-native-validation.tsx +85 -0
  221. package/zod/src/__tests__/Form.tsx +54 -0
  222. package/zod/src/__tests__/__fixtures__/data.ts +81 -0
  223. package/zod/src/__tests__/__snapshots__/zod.ts.snap +377 -0
  224. package/zod/src/__tests__/zod.ts +77 -0
  225. package/zod/src/index.ts +2 -0
  226. package/zod/src/types.ts +16 -0
  227. package/zod/src/zod.ts +85 -0
@@ -0,0 +1,85 @@
1
+ import React from 'react';
2
+ import { render, screen, act } from '@testing-library/react';
3
+ import user from '@testing-library/user-event';
4
+ import { useForm } from 'react-hook-form';
5
+ import * as Yup from 'yup';
6
+ import { yupResolver } from '..';
7
+
8
+ const USERNAME_REQUIRED_MESSAGE = 'username field is required';
9
+ const PASSWORD_REQUIRED_MESSAGE = 'password field is required';
10
+
11
+ const schema = Yup.object({
12
+ username: Yup.string().required(USERNAME_REQUIRED_MESSAGE),
13
+ password: Yup.string().required(PASSWORD_REQUIRED_MESSAGE),
14
+ });
15
+
16
+ type FormData = Yup.InferType<typeof schema>;
17
+
18
+ interface Props {
19
+ onSubmit: (data: FormData) => void;
20
+ }
21
+
22
+ function TestComponent({ onSubmit }: Props) {
23
+ const { register, handleSubmit } = useForm({
24
+ resolver: yupResolver(schema),
25
+ shouldUseNativeValidation: true,
26
+ });
27
+
28
+ return (
29
+ <form onSubmit={handleSubmit(onSubmit)}>
30
+ <input {...register('username')} placeholder="username" />
31
+
32
+ <input {...register('password')} placeholder="password" />
33
+
34
+ <button type="submit">submit</button>
35
+ </form>
36
+ );
37
+ }
38
+
39
+ test("form's native validation with Yup", async () => {
40
+ const handleSubmit = jest.fn();
41
+ render(<TestComponent onSubmit={handleSubmit} />);
42
+
43
+ // username
44
+ let usernameField = screen.getByPlaceholderText(
45
+ /username/i,
46
+ ) as HTMLInputElement;
47
+ expect(usernameField.validity.valid).toBe(true);
48
+ expect(usernameField.validationMessage).toBe('');
49
+
50
+ // password
51
+ let passwordField = screen.getByPlaceholderText(
52
+ /password/i,
53
+ ) as HTMLInputElement;
54
+ expect(passwordField.validity.valid).toBe(true);
55
+ expect(passwordField.validationMessage).toBe('');
56
+
57
+ await act(async () => {
58
+ user.click(screen.getByText(/submit/i));
59
+ });
60
+
61
+ // username
62
+ usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
63
+ expect(usernameField.validity.valid).toBe(false);
64
+ expect(usernameField.validationMessage).toBe(USERNAME_REQUIRED_MESSAGE);
65
+
66
+ // password
67
+ passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
68
+ expect(passwordField.validity.valid).toBe(false);
69
+ expect(passwordField.validationMessage).toBe(PASSWORD_REQUIRED_MESSAGE);
70
+
71
+ await act(async () => {
72
+ user.type(screen.getByPlaceholderText(/username/i), 'joe');
73
+ user.type(screen.getByPlaceholderText(/password/i), 'password');
74
+ });
75
+
76
+ // username
77
+ usernameField = screen.getByPlaceholderText(/username/i) as HTMLInputElement;
78
+ expect(usernameField.validity.valid).toBe(true);
79
+ expect(usernameField.validationMessage).toBe('');
80
+
81
+ // password
82
+ passwordField = screen.getByPlaceholderText(/password/i) as HTMLInputElement;
83
+ expect(passwordField.validity.valid).toBe(true);
84
+ expect(passwordField.validationMessage).toBe('');
85
+ });
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { render, screen, act } from '@testing-library/react';
3
+ import user from '@testing-library/user-event';
4
+ import { useForm } from 'react-hook-form';
5
+ import * as Yup from 'yup';
6
+ import { yupResolver } from '..';
7
+
8
+ const schema = Yup.object({
9
+ username: Yup.string().required(),
10
+ password: Yup.string().required(),
11
+ });
12
+
13
+ type FormData = Yup.InferType<typeof schema> & { unusedProperty: string };
14
+
15
+ interface Props {
16
+ onSubmit: (data: FormData) => void;
17
+ }
18
+
19
+ function TestComponent({ onSubmit }: Props) {
20
+ const {
21
+ register,
22
+ formState: { errors },
23
+ handleSubmit,
24
+ } = useForm({
25
+ resolver: yupResolver(schema), // Useful to check TypeScript regressions
26
+ });
27
+
28
+ return (
29
+ <form onSubmit={handleSubmit(onSubmit)}>
30
+ <input {...register('username')} />
31
+ {errors.username && <span role="alert">{errors.username.message}</span>}
32
+
33
+ <input {...register('password')} />
34
+ {errors.password && <span role="alert">{errors.password.message}</span>}
35
+
36
+ <button type="submit">submit</button>
37
+ </form>
38
+ );
39
+ }
40
+
41
+ test("form's validation with Yup and TypeScript's integration", async () => {
42
+ const handleSubmit = jest.fn();
43
+ render(<TestComponent onSubmit={handleSubmit} />);
44
+
45
+ expect(screen.queryAllByRole(/alert/i)).toHaveLength(0);
46
+
47
+ await act(async () => {
48
+ user.click(screen.getByText(/submit/i));
49
+ });
50
+
51
+ expect(screen.getByText(/username is a required field/i)).toBeInTheDocument();
52
+ expect(screen.getByText(/password is a required field/i)).toBeInTheDocument();
53
+ expect(handleSubmit).not.toHaveBeenCalled();
54
+ });
@@ -0,0 +1,72 @@
1
+ import { Field, InternalFieldName } from 'react-hook-form';
2
+ import * as yup from 'yup';
3
+
4
+ export const schema = yup.object({
5
+ username: yup.string().matches(/^\w+$/).min(3).max(30).required(),
6
+ password: yup
7
+ .string()
8
+ .matches(new RegExp('.*[A-Z].*'), 'One uppercase character')
9
+ .matches(new RegExp('.*[a-z].*'), 'One lowercase character')
10
+ .matches(new RegExp('.*\\d.*'), 'One number')
11
+ .matches(
12
+ new RegExp('.*[`~<>?,./!@#$%^&*()\\-_+="\'|{}\\[\\];:\\\\].*'),
13
+ 'One special character',
14
+ )
15
+ .min(8, 'Must be at least 8 characters in length')
16
+ .required('New Password is required'),
17
+ repeatPassword: yup.ref('password'),
18
+ accessToken: yup.string(),
19
+ birthYear: yup.number().min(1900).max(2013),
20
+ email: yup.string().email(),
21
+ tags: yup.array(yup.string()),
22
+ enabled: yup.boolean(),
23
+ like: yup.array().of(
24
+ yup.object({
25
+ id: yup.number().required(),
26
+ name: yup.string().length(4).required(),
27
+ }),
28
+ ),
29
+ });
30
+
31
+ export const validData: yup.InferType<typeof schema> = {
32
+ username: 'Doe',
33
+ password: 'Password123_',
34
+ repeatPassword: 'Password123_',
35
+ birthYear: 2000,
36
+ email: 'john@doe.com',
37
+ tags: ['tag1', 'tag2'],
38
+ enabled: true,
39
+ accessToken: 'accessToken',
40
+ like: [
41
+ {
42
+ id: 1,
43
+ name: 'name',
44
+ },
45
+ ],
46
+ };
47
+
48
+ export const invalidData = {
49
+ password: '___',
50
+ email: '',
51
+ birthYear: 'birthYear',
52
+ like: [{ id: 'z' }],
53
+ };
54
+
55
+ export const fields: Record<InternalFieldName, Field['_f']> = {
56
+ username: {
57
+ ref: { name: 'username' },
58
+ name: 'username',
59
+ },
60
+ password: {
61
+ ref: { name: 'password' },
62
+ name: 'password',
63
+ },
64
+ email: {
65
+ ref: { name: 'email' },
66
+ name: 'email',
67
+ },
68
+ birthday: {
69
+ ref: { name: 'birthday' },
70
+ name: 'birthday',
71
+ },
72
+ };
@@ -0,0 +1,231 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`yupResolver should return a single error from yupResolver when validation fails 1`] = `
4
+ Object {
5
+ "errors": Object {
6
+ "birthYear": Object {
7
+ "message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
8
+ "ref": undefined,
9
+ "type": "typeError",
10
+ },
11
+ "like": Array [
12
+ Object {
13
+ "id": Object {
14
+ "message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
15
+ "ref": undefined,
16
+ "type": "typeError",
17
+ },
18
+ "name": Object {
19
+ "message": "like[0].name is a required field",
20
+ "ref": undefined,
21
+ "type": "required",
22
+ },
23
+ },
24
+ ],
25
+ "password": Object {
26
+ "message": "One uppercase character",
27
+ "ref": Object {
28
+ "name": "password",
29
+ },
30
+ "type": "matches",
31
+ },
32
+ "username": Object {
33
+ "message": "username is a required field",
34
+ "ref": Object {
35
+ "name": "username",
36
+ },
37
+ "type": "required",
38
+ },
39
+ },
40
+ "values": Object {},
41
+ }
42
+ `;
43
+
44
+ exports[`yupResolver should return a single error from yupResolver with \`mode: sync\` when validation fails 1`] = `
45
+ Object {
46
+ "errors": Object {
47
+ "birthYear": Object {
48
+ "message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
49
+ "ref": undefined,
50
+ "type": "typeError",
51
+ },
52
+ "like": Array [
53
+ Object {
54
+ "id": Object {
55
+ "message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
56
+ "ref": undefined,
57
+ "type": "typeError",
58
+ },
59
+ "name": Object {
60
+ "message": "like[0].name is a required field",
61
+ "ref": undefined,
62
+ "type": "required",
63
+ },
64
+ },
65
+ ],
66
+ "password": Object {
67
+ "message": "One uppercase character",
68
+ "ref": Object {
69
+ "name": "password",
70
+ },
71
+ "type": "matches",
72
+ },
73
+ "username": Object {
74
+ "message": "username is a required field",
75
+ "ref": Object {
76
+ "name": "username",
77
+ },
78
+ "type": "required",
79
+ },
80
+ },
81
+ "values": Object {},
82
+ }
83
+ `;
84
+
85
+ exports[`yupResolver should return all the errors from yupResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
86
+ Object {
87
+ "errors": Object {
88
+ "birthYear": Object {
89
+ "message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
90
+ "ref": undefined,
91
+ "type": "typeError",
92
+ "types": Object {
93
+ "typeError": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
94
+ },
95
+ },
96
+ "like": Array [
97
+ Object {
98
+ "id": Object {
99
+ "message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
100
+ "ref": undefined,
101
+ "type": "typeError",
102
+ "types": Object {
103
+ "typeError": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
104
+ },
105
+ },
106
+ "name": Object {
107
+ "message": "like[0].name is a required field",
108
+ "ref": undefined,
109
+ "type": "required",
110
+ "types": Object {
111
+ "required": "like[0].name is a required field",
112
+ },
113
+ },
114
+ },
115
+ ],
116
+ "password": Object {
117
+ "message": "One uppercase character",
118
+ "ref": Object {
119
+ "name": "password",
120
+ },
121
+ "type": "matches",
122
+ "types": Object {
123
+ "matches": Array [
124
+ "One uppercase character",
125
+ "One lowercase character",
126
+ "One number",
127
+ ],
128
+ "min": "Must be at least 8 characters in length",
129
+ },
130
+ },
131
+ "username": Object {
132
+ "message": "username is a required field",
133
+ "ref": Object {
134
+ "name": "username",
135
+ },
136
+ "type": "required",
137
+ "types": Object {
138
+ "required": "username is a required field",
139
+ },
140
+ },
141
+ },
142
+ "values": Object {},
143
+ }
144
+ `;
145
+
146
+ exports[`yupResolver should return all the errors from yupResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = `
147
+ Object {
148
+ "errors": Object {
149
+ "birthYear": Object {
150
+ "message": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
151
+ "ref": undefined,
152
+ "type": "typeError",
153
+ "types": Object {
154
+ "typeError": "birthYear must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"birthYear\\"\`).",
155
+ },
156
+ },
157
+ "like": Array [
158
+ Object {
159
+ "id": Object {
160
+ "message": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
161
+ "ref": undefined,
162
+ "type": "typeError",
163
+ "types": Object {
164
+ "typeError": "like[0].id must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"z\\"\`).",
165
+ },
166
+ },
167
+ "name": Object {
168
+ "message": "like[0].name is a required field",
169
+ "ref": undefined,
170
+ "type": "required",
171
+ "types": Object {
172
+ "required": "like[0].name is a required field",
173
+ },
174
+ },
175
+ },
176
+ ],
177
+ "password": Object {
178
+ "message": "One uppercase character",
179
+ "ref": Object {
180
+ "name": "password",
181
+ },
182
+ "type": "matches",
183
+ "types": Object {
184
+ "matches": Array [
185
+ "One uppercase character",
186
+ "One lowercase character",
187
+ "One number",
188
+ ],
189
+ "min": "Must be at least 8 characters in length",
190
+ },
191
+ },
192
+ "username": Object {
193
+ "message": "username is a required field",
194
+ "ref": Object {
195
+ "name": "username",
196
+ },
197
+ "type": "required",
198
+ "types": Object {
199
+ "required": "username is a required field",
200
+ },
201
+ },
202
+ },
203
+ "values": Object {},
204
+ }
205
+ `;
206
+
207
+ exports[`yupResolver should return an error from yupResolver when validation fails and pass down the yup context 1`] = `
208
+ Object {
209
+ "errors": Object {
210
+ "name": Object {
211
+ "message": "name must be at least 6 characters",
212
+ "ref": undefined,
213
+ "type": "min",
214
+ },
215
+ },
216
+ "values": Object {},
217
+ }
218
+ `;
219
+
220
+ exports[`yupResolver should return correct error message with using yup.test 1`] = `
221
+ Object {
222
+ "errors": Object {
223
+ "": Object {
224
+ "message": "Email or name are required",
225
+ "ref": undefined,
226
+ "type": "name",
227
+ },
228
+ },
229
+ "values": Object {},
230
+ }
231
+ `;
@@ -0,0 +1,174 @@
1
+ /* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
2
+ import * as yup from 'yup';
3
+ import { yupResolver } from '..';
4
+ import { schema, validData, fields, invalidData } from './__fixtures__/data';
5
+
6
+ const shouldUseNativeValidation = false;
7
+
8
+ describe('yupResolver', () => {
9
+ it('should return values from yupResolver when validation pass', async () => {
10
+ const schemaSpy = jest.spyOn(schema, 'validate');
11
+ const schemaSyncSpy = jest.spyOn(schema, 'validateSync');
12
+
13
+ const result = await yupResolver(schema)(validData, undefined, {
14
+ fields,
15
+ shouldUseNativeValidation,
16
+ });
17
+
18
+ expect(schemaSpy).toHaveBeenCalledTimes(1);
19
+ expect(schemaSyncSpy).not.toHaveBeenCalled();
20
+ expect(result).toEqual({ errors: {}, values: validData });
21
+ });
22
+
23
+ it('should return values from yupResolver with `mode: sync` when validation pass', async () => {
24
+ const validateSyncSpy = jest.spyOn(schema, 'validateSync');
25
+ const validateSpy = jest.spyOn(schema, 'validate');
26
+
27
+ const result = await yupResolver(schema, undefined, {
28
+ mode: 'sync',
29
+ })(validData, undefined, { fields, shouldUseNativeValidation });
30
+
31
+ expect(validateSyncSpy).toHaveBeenCalledTimes(1);
32
+ expect(validateSpy).not.toHaveBeenCalled();
33
+ expect(result).toEqual({ errors: {}, values: validData });
34
+ });
35
+
36
+ it('should return a single error from yupResolver when validation fails', async () => {
37
+ const result = await yupResolver(schema)(invalidData, undefined, {
38
+ fields,
39
+ shouldUseNativeValidation,
40
+ });
41
+
42
+ expect(result).toMatchSnapshot();
43
+ });
44
+
45
+ it('should return a single error from yupResolver with `mode: sync` when validation fails', async () => {
46
+ const validateSyncSpy = jest.spyOn(schema, 'validateSync');
47
+ const validateSpy = jest.spyOn(schema, 'validate');
48
+
49
+ const result = await yupResolver(schema, undefined, {
50
+ mode: 'sync',
51
+ })(invalidData, undefined, { fields, shouldUseNativeValidation });
52
+
53
+ expect(validateSyncSpy).toHaveBeenCalledTimes(1);
54
+ expect(validateSpy).not.toHaveBeenCalled();
55
+ expect(result).toMatchSnapshot();
56
+ });
57
+
58
+ it('should return all the errors from yupResolver when validation fails with `validateAllFieldCriteria` set to true', async () => {
59
+ const result = await yupResolver(schema)(invalidData, undefined, {
60
+ fields,
61
+ criteriaMode: 'all',
62
+ shouldUseNativeValidation,
63
+ });
64
+
65
+ expect(result).toMatchSnapshot();
66
+ });
67
+
68
+ it('should return all the errors from yupResolver when validation fails with `validateAllFieldCriteria` set to true and `mode: sync`', async () => {
69
+ const result = await yupResolver(schema, undefined, { mode: 'sync' })(
70
+ invalidData,
71
+ undefined,
72
+ {
73
+ fields,
74
+ criteriaMode: 'all',
75
+ shouldUseNativeValidation,
76
+ },
77
+ );
78
+
79
+ expect(result).toMatchSnapshot();
80
+ });
81
+
82
+ it('should return an error from yupResolver when validation fails and pass down the yup context', async () => {
83
+ const data = { name: 'eric' };
84
+ const context = { min: true };
85
+ const schemaWithContext = yup.object({
86
+ name: yup
87
+ .string()
88
+ .required()
89
+ .when('$min', (min: boolean, schema: yup.StringSchema) => {
90
+ return min ? schema.min(6) : schema;
91
+ }),
92
+ });
93
+
94
+ const validateSpy = jest.spyOn(schemaWithContext, 'validate');
95
+
96
+ const result = await yupResolver(schemaWithContext)(data, context, {
97
+ fields,
98
+ shouldUseNativeValidation,
99
+ });
100
+ expect(validateSpy).toHaveBeenCalledTimes(1);
101
+ expect(validateSpy).toHaveBeenCalledWith(
102
+ data,
103
+ expect.objectContaining({
104
+ abortEarly: false,
105
+ context,
106
+ }),
107
+ );
108
+ expect(result).toMatchSnapshot();
109
+ });
110
+
111
+ it('should show a warning log if yup context is used instead only on dev environment', async () => {
112
+ jest.spyOn(console, 'warn').mockImplementation(jest.fn);
113
+ process.env.NODE_ENV = 'development';
114
+
115
+ await yupResolver(yup.object(), { context: { noContext: true } })(
116
+ {},
117
+ undefined,
118
+ {
119
+ fields,
120
+ shouldUseNativeValidation,
121
+ },
122
+ );
123
+ expect(console.warn).toHaveBeenCalledWith(
124
+ "You should not used the yup options context. Please, use the 'useForm' context object instead",
125
+ );
126
+ process.env.NODE_ENV = 'test';
127
+ });
128
+
129
+ it('should not show a warning log if yup context is used instead only on production environment', async () => {
130
+ jest.spyOn(console, 'warn').mockImplementation(jest.fn);
131
+ process.env.NODE_ENV = 'production';
132
+
133
+ await yupResolver(yup.object(), { context: { noContext: true } })(
134
+ {},
135
+ undefined,
136
+ { fields, shouldUseNativeValidation },
137
+ );
138
+ expect(console.warn).not.toHaveBeenCalled();
139
+ process.env.NODE_ENV = 'test';
140
+ });
141
+
142
+ it('should return correct error message with using yup.test', async () => {
143
+ const result = await yupResolver(
144
+ yup
145
+ .object({
146
+ name: yup.string(),
147
+ email: yup.string(),
148
+ })
149
+ .test(
150
+ 'name',
151
+ 'Email or name are required',
152
+ (value) => !!(value && (value.name || value.email)),
153
+ ),
154
+ )({ name: '', email: '' }, undefined, {
155
+ fields,
156
+ shouldUseNativeValidation,
157
+ });
158
+
159
+ expect(result).toMatchSnapshot();
160
+ });
161
+
162
+ it("should merge default yup resolver options with yup's options", async () => {
163
+ const validateSpy = jest.spyOn(schema, 'validate');
164
+
165
+ await yupResolver(schema, { stripUnknown: true })(invalidData, undefined, {
166
+ fields,
167
+ shouldUseNativeValidation,
168
+ });
169
+
170
+ expect(validateSpy.mock.calls[0][1]).toEqual(
171
+ expect.objectContaining({ stripUnknown: true, abortEarly: false }),
172
+ );
173
+ });
174
+ });
@@ -0,0 +1,2 @@
1
+ export * from './yup';
2
+ export * from './types';
@@ -0,0 +1,21 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import { ResolverOptions, ResolverResult } from 'react-hook-form';
3
+ import * as Yup from 'yup';
4
+ import type Lazy from 'yup/lib/Lazy';
5
+
6
+ type Options<T extends Yup.AnyObjectSchema | Lazy<any>> = Parameters<
7
+ T['validate']
8
+ >[1];
9
+
10
+ export type Resolver = <
11
+ T extends Yup.AnyObjectSchema | Lazy<any>,
12
+ TContext extends object = object,
13
+ >(
14
+ schema: T,
15
+ schemaOptions?: Options<T>,
16
+ factoryOptions?: { mode?: 'async' | 'sync' },
17
+ ) => (
18
+ values: unknown,
19
+ context: TContext | undefined,
20
+ options: ResolverOptions<Yup.InferType<T>>,
21
+ ) => Promise<ResolverResult<Yup.InferType<T>>>;