Skip to content

Commit e76743d

Browse files
authored
feat: add Vest sync validation + update to v3 (#117)
1 parent f83996b commit e76743d

File tree

6 files changed

+384
-205
lines changed

6 files changed

+384
-205
lines changed

package.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,18 @@
109109
},
110110
"homepage": "https://react-hook-form.com",
111111
"devDependencies": {
112-
"@testing-library/jest-dom": "^5.11.8",
113-
"@testing-library/react": "^11.2.2",
114-
"@testing-library/user-event": "^12.6.0",
115-
"@types/jest": "^26.0.19",
112+
"@testing-library/jest-dom": "^5.11.9",
113+
"@testing-library/react": "^11.2.3",
114+
"@testing-library/user-event": "^12.6.2",
115+
"@types/jest": "^26.0.20",
116116
"@types/react": "^17.0.0",
117-
"@typescript-eslint/eslint-plugin": "^4.11.1",
118-
"@typescript-eslint/parser": "^4.11.1",
117+
"@typescript-eslint/eslint-plugin": "^4.14.0",
118+
"@typescript-eslint/parser": "^4.14.0",
119119
"check-export-map": "^1.0.1",
120-
"eslint": "^7.17.0",
121-
"eslint-config-prettier": "^7.1.0",
122-
"eslint-plugin-prettier": "^3.3.0",
123-
"husky": "^4.3.6",
120+
"eslint": "^7.18.0",
121+
"eslint-config-prettier": "^7.2.0",
122+
"eslint-plugin-prettier": "^3.3.1",
123+
"husky": "^4.3.8",
124124
"jest": "^26.6.3",
125125
"joi": "^17.3.0",
126126
"lint-staged": "^10.5.3",
@@ -129,12 +129,12 @@
129129
"prettier": "^2.2.1",
130130
"react": "^17.0.1",
131131
"react-dom": "^17.0.1",
132-
"react-hook-form": "^6.14.0",
133-
"semantic-release": "^17.3.1",
134-
"superstruct": "^0.13.1",
132+
"react-hook-form": "^6.14.2",
133+
"semantic-release": "^17.3.6",
134+
"superstruct": "^0.13.3",
135135
"ts-jest": "^26.4.4",
136136
"typescript": "^4.1.3",
137-
"vest": "^2.2.3",
137+
"vest": "^3.1.1",
138138
"yup": "^0.32.8",
139139
"zod": "^1.11.11"
140140
},
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`vestResolver should return all the error messages from vestResolver when validation fails and validateAllFieldCriteria set to true 1`] = `
4+
Object {
5+
"errors": Object {
6+
"deepObject": Object {
7+
"data": Object {
8+
"message": "deepObject.data is required",
9+
"type": "",
10+
"types": Object {
11+
"0": "deepObject.data is required",
12+
},
13+
},
14+
},
15+
"password": Object {
16+
"message": "Password must be at least 5 chars",
17+
"type": "",
18+
"types": Object {
19+
"0": "Password must be at least 5 chars",
20+
"1": "Password must contain a digit",
21+
"2": "Password must contain a symbol",
22+
},
23+
},
24+
"username": Object {
25+
"message": "Username is required",
26+
"type": "",
27+
"types": Object {
28+
"0": "Username is required",
29+
"1": "Must be longer than 3 chars",
30+
},
31+
},
32+
},
33+
"values": Object {},
34+
}
35+
`;
36+
37+
exports[`vestResolver should return all the error messages from vestResolver when validation fails and validateAllFieldCriteria set to true and \`mode: sync\` 1`] = `
38+
Object {
39+
"errors": Object {
40+
"deepObject": Object {
41+
"data": Object {
42+
"message": "deepObject.data is required",
43+
"type": "",
44+
"types": Object {
45+
"0": "deepObject.data is required",
46+
},
47+
},
48+
},
49+
"password": Object {
50+
"message": "Password must be at least 5 chars",
51+
"type": "",
52+
"types": Object {
53+
"0": "Password must be at least 5 chars",
54+
"1": "Password must contain a digit",
55+
"2": "Password must contain a symbol",
56+
},
57+
},
58+
"username": Object {
59+
"message": "Username is required",
60+
"type": "",
61+
"types": Object {
62+
"0": "Username is required",
63+
"1": "Must be longer than 3 chars",
64+
},
65+
},
66+
},
67+
"values": Object {},
68+
}
69+
`;
70+
71+
exports[`vestResolver should return single error message from vestResolver when validation fails and validateAllFieldCriteria set to false 1`] = `
72+
Object {
73+
"errors": Object {
74+
"deepObject": Object {
75+
"data": Object {
76+
"message": "deepObject.data is required",
77+
"type": "",
78+
},
79+
},
80+
"password": Object {
81+
"message": "Password must be at least 5 chars",
82+
"type": "",
83+
},
84+
"username": Object {
85+
"message": "Username is required",
86+
"type": "",
87+
},
88+
},
89+
"values": Object {},
90+
}
91+
`;
92+
93+
exports[`vestResolver should return single error message from vestResolver when validation fails and validateAllFieldCriteria set to false and \`mode: sync\` 1`] = `
94+
Object {
95+
"errors": Object {
96+
"deepObject": Object {
97+
"data": Object {
98+
"message": "deepObject.data is required",
99+
"type": "",
100+
},
101+
},
102+
"password": Object {
103+
"message": "Password must be at least 5 chars",
104+
"type": "",
105+
},
106+
"username": Object {
107+
"message": "Username is required",
108+
"type": "",
109+
},
110+
},
111+
"values": Object {},
112+
}
113+
`;

vest/src/__tests__/vest.ts

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,23 @@ describe('vestResolver', () => {
4040
data: 'test',
4141
},
4242
};
43-
expect(await vestResolver(validationSuite)(data, {})).toEqual({
43+
expect(await vestResolver(validationSuite)(data)).toEqual({
44+
values: data,
45+
errors: {},
46+
});
47+
});
48+
49+
it('should return values from vestResolver with `mode: sync` when validation pass', async () => {
50+
const data = {
51+
username: 'asdda',
52+
password: 'asddfg123!',
53+
deepObject: {
54+
data: 'test',
55+
},
56+
};
57+
expect(
58+
await vestResolver(validationSuite, undefined, { mode: 'sync' })(data),
59+
).toEqual({
4460
values: data,
4561
errors: {},
4662
});
@@ -55,25 +71,21 @@ describe('vestResolver', () => {
5571
},
5672
};
5773

58-
expect(await vestResolver(validationSuite)(data, {})).toEqual({
59-
values: {},
60-
errors: {
61-
username: {
62-
type: '',
63-
message: 'Username is required',
64-
},
65-
password: {
66-
type: '',
67-
message: 'Password must be at least 5 chars',
68-
},
69-
deepObject: {
70-
data: {
71-
type: '',
72-
message: 'deepObject.data is required',
73-
},
74-
},
74+
expect(await vestResolver(validationSuite)(data)).toMatchSnapshot();
75+
});
76+
77+
it('should return single error message from vestResolver when validation fails and validateAllFieldCriteria set to false and `mode: sync`', async () => {
78+
const data = {
79+
username: '',
80+
password: 'a',
81+
deepObject: {
82+
data: '',
7583
},
76-
});
84+
};
85+
86+
expect(
87+
await vestResolver(validationSuite, undefined, { mode: 'sync' })(data),
88+
).toMatchSnapshot();
7789
});
7890

7991
it('should return all the error messages from vestResolver when validation fails and validateAllFieldCriteria set to true', async () => {
@@ -85,36 +97,26 @@ describe('vestResolver', () => {
8597
},
8698
};
8799

88-
expect(await vestResolver(validationSuite, {})(data, {}, true)).toEqual({
89-
values: {},
90-
errors: {
91-
username: {
92-
type: '',
93-
message: 'Username is required',
94-
types: {
95-
0: 'Username is required',
96-
1: 'Must be longer than 3 chars',
97-
},
98-
},
99-
password: {
100-
type: '',
101-
message: 'Password must be at least 5 chars',
102-
types: {
103-
0: 'Password must be at least 5 chars',
104-
1: 'Password must contain a digit',
105-
2: 'Password must contain a symbol',
106-
},
107-
},
108-
deepObject: {
109-
data: {
110-
type: '',
111-
message: 'deepObject.data is required',
112-
types: {
113-
0: 'deepObject.data is required',
114-
},
115-
},
116-
},
100+
expect(
101+
await vestResolver(validationSuite)(data, {}, true),
102+
).toMatchSnapshot();
103+
});
104+
105+
it('should return all the error messages from vestResolver when validation fails and validateAllFieldCriteria set to true and `mode: sync`', async () => {
106+
const data = {
107+
username: '',
108+
password: 'a',
109+
deepObject: {
110+
data: '',
117111
},
118-
});
112+
};
113+
114+
expect(
115+
await vestResolver(validationSuite, undefined, { mode: 'sync' })(
116+
data,
117+
{},
118+
true,
119+
),
120+
).toMatchSnapshot();
119121
});
120122
});

vest/src/types.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@ export type ICreateResult = ReturnType<typeof Vest.create>;
99

1010
export type Resolver = (
1111
schema: ICreateResult,
12-
options?: any,
12+
schemaOptions?: never,
13+
resolverOptions?: { mode: 'async' | 'sync' },
1314
) => <TFieldValues extends FieldValues, TContext>(
1415
values: UnpackNestedValue<TFieldValues>,
1516
context?: TContext,
1617
validateAllFieldCriteria?: boolean,
1718
) => Promise<ResolverResult<TFieldValues>>;
1819

1920
export type VestErrors = Record<string, string[]>;
20-
21-
export type Promisify = <T extends ICreateResult, K>(
22-
fn: T,
23-
) => (args: K) => Promise<Vest.IVestResult>;

vest/src/vest.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { transformToNestObject } from 'react-hook-form';
2-
import * as Vest from 'vest';
3-
import type { Promisify, VestErrors, Resolver } from './types';
4-
5-
const promisify: Promisify = (validatorFn) => (...args) =>
6-
new Promise((resolve) => validatorFn(...args).done(resolve as Vest.DoneCB));
2+
import promisify from 'vest/promisify';
3+
import { DraftResult, IVestResult } from 'vest/vestResult';
4+
import type { VestErrors, Resolver } from './types';
75

86
const parseErrorSchema = (
97
vestError: VestErrors,
@@ -30,17 +28,23 @@ const parseErrorSchema = (
3028
}, {});
3129
};
3230

33-
export const vestResolver: Resolver = (schema, _ = {}) => async (
34-
values,
35-
_context,
36-
validateAllFieldCriteria = false,
37-
) => {
38-
const validateSchema = promisify(schema);
39-
const result = await validateSchema(values);
31+
export const vestResolver: Resolver = (
32+
schema,
33+
_,
34+
{ mode } = { mode: 'async' },
35+
) => async (values, _context, validateAllFieldCriteria = false) => {
36+
let result: IVestResult | DraftResult;
37+
if (mode === 'async') {
38+
const validateSchema = promisify(schema);
39+
result = await validateSchema(values);
40+
} else {
41+
result = schema(values);
42+
}
43+
4044
const errors = result.getErrors();
4145

4246
if (!result.hasErrors()) {
43-
return { values: values as any, errors: {} };
47+
return { values, errors: {} };
4448
}
4549

4650
return {

0 commit comments

Comments
 (0)