Skip to content

Commit 6677e0e

Browse files
authored
fix: resolvers fails silently (#528)
1 parent 2749bd9 commit 6677e0e

File tree

11 files changed

+129
-37
lines changed

11 files changed

+129
-37
lines changed

computed-types/src/__tests__/computed-types.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,20 @@ describe('computedTypesResolver', () => {
2121

2222
expect(result).toMatchSnapshot();
2323
});
24+
25+
it('should throw any error unrelated to computed-types', async () => {
26+
const schemaWithCustomError = schema.transform(() => {
27+
throw Error('custom error');
28+
});
29+
const promise = computedTypesResolver(schemaWithCustomError)(
30+
validData,
31+
undefined,
32+
{
33+
fields,
34+
shouldUseNativeValidation,
35+
},
36+
);
37+
38+
await expect(promise).rejects.toThrow('custom error');
39+
});
2440
});

computed-types/src/computed-types.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import type { FieldErrors } from 'react-hook-form';
22
import { toNestError, validateFieldsNatively } from '@hookform/resolvers';
3-
import type { ValidationError } from 'computed-types';
43
import type { Resolver } from './types';
4+
import type { ValidationError } from 'computed-types';
5+
6+
const isValidationError = (error: any): error is ValidationError =>
7+
error.errors != null;
58

69
const parseErrorSchema = (computedTypesError: ValidationError) => {
710
const parsedErrors: FieldErrors = {};
@@ -27,9 +30,13 @@ export const computedTypesResolver: Resolver =
2730
values: data,
2831
};
2932
} catch (error: any) {
30-
return {
31-
values: {},
32-
errors: toNestError(parseErrorSchema(error), options),
33-
};
33+
if (isValidationError(error)) {
34+
return {
35+
values: {},
36+
errors: toNestError(parseErrorSchema(error), options),
37+
};
38+
}
39+
40+
throw error;
3441
}
3542
};

superstruct/src/__tests__/superstruct.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,17 @@ describe('superstructResolver', () => {
2121

2222
expect(result).toMatchSnapshot();
2323
});
24+
25+
it('should return values from superstructResolver when validation pass & raw=true', async () => {
26+
const result = await superstructResolver(schema, undefined, { raw: true })(
27+
validData,
28+
undefined,
29+
{
30+
fields,
31+
shouldUseNativeValidation,
32+
},
33+
);
34+
35+
expect(result).toEqual({ errors: {}, values: validData });
36+
});
2437
});

superstruct/src/superstruct.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ const parseErrorSchema = (error: StructError) =>
1515
);
1616

1717
export const superstructResolver: Resolver =
18-
(schema, resolverOptions) => (values, _, options) => {
19-
const result = validate(values, schema, resolverOptions);
18+
(schema, schemaOptions, resolverOptions = {}) =>
19+
(values, _, options) => {
20+
const result = validate(values, schema, schemaOptions);
2021

2122
if (result[0]) {
2223
return {
@@ -28,7 +29,7 @@ export const superstructResolver: Resolver =
2829
options.shouldUseNativeValidation && validateFieldsNatively({}, options);
2930

3031
return {
31-
values: result[1],
32+
values: resolverOptions.raw ? values : result[1],
3233
errors: {},
3334
};
3435
};

superstruct/src/types.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import {
2-
FieldValues,
3-
ResolverOptions,
4-
ResolverResult,
5-
} from 'react-hook-form';
1+
import { FieldValues, ResolverOptions, ResolverResult } from 'react-hook-form';
62
import { validate, Struct } from 'superstruct';
73

84
type Options = Parameters<typeof validate>[2];
95

106
export type Resolver = <T extends Struct<any, any>>(
117
schema: T,
128
options?: Options,
9+
factoryOptions?: {
10+
/**
11+
* Return the raw input values rather than the parsed values.
12+
* @default false
13+
*/
14+
raw?: boolean;
15+
},
1316
) => <TFieldValues extends FieldValues, TContext>(
1417
values: TFieldValues,
1518
context: TContext | undefined,

yup/src/__tests__/yup.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,34 @@ describe('yupResolver', () => {
190190

191191
expect(result).toMatchSnapshot();
192192
});
193+
194+
it('should throw any error unrelated to Yup', async () => {
195+
const schemaWithCustomError = schema.transform(() => {
196+
throw Error('custom error');
197+
});
198+
const promise = yupResolver(schemaWithCustomError)(validData, undefined, {
199+
fields,
200+
shouldUseNativeValidation,
201+
});
202+
203+
await expect(promise).rejects.toThrow('custom error');
204+
});
205+
206+
it('should return values from yupResolver when validation pass & raw=true', async () => {
207+
const schemaSpy = vi.spyOn(schema, 'validate');
208+
const schemaSyncSpy = vi.spyOn(schema, 'validateSync');
209+
210+
const result = await yupResolver(schema, undefined, { raw: true })(
211+
validData,
212+
undefined,
213+
{
214+
fields,
215+
shouldUseNativeValidation,
216+
},
217+
);
218+
219+
expect(schemaSpy).toHaveBeenCalledTimes(1);
220+
expect(schemaSyncSpy).not.toHaveBeenCalled();
221+
expect(result).toEqual({ errors: {}, values: validData });
222+
});
193223
});

yup/src/types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,17 @@ type Options<T extends Yup.ObjectSchema<any>> = Parameters<T['validate']>[1];
66
export type Resolver = <T extends Yup.ObjectSchema<any>>(
77
schema: T,
88
schemaOptions?: Options<T>,
9-
factoryOptions?: { mode?: 'async' | 'sync'; rawValues?: boolean },
9+
factoryOptions?: {
10+
/**
11+
* @default async
12+
*/
13+
mode?: 'async' | 'sync';
14+
/**
15+
* Return the raw input values rather than the parsed values.
16+
* @default false
17+
*/
18+
raw?: boolean;
19+
},
1020
) => <TFieldValues extends FieldValues, TContext>(
1121
values: TFieldValues,
1222
context: TContext | undefined,

yup/src/yup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const yupResolver: Resolver =
5959
options.shouldUseNativeValidation && validateFieldsNatively({}, options);
6060

6161
return {
62-
values: resolverOptions.rawValues ? values : result,
62+
values: resolverOptions.raw ? values : result,
6363
errors: {},
6464
};
6565
} catch (e: any) {

zod/src/__tests__/zod.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { schema, validData, invalidData, fields } from './__fixtures__/data';
44
const shouldUseNativeValidation = false;
55

66
describe('zodResolver', () => {
7-
it('should return values from zodResolver when validation pass & rawValues=true', async () => {
7+
it('should return values from zodResolver when validation pass & raw=true', async () => {
88
const parseAsyncSpy = vi.spyOn(schema, 'parseAsync');
99

1010
const result = await zodResolver(schema, undefined, {
11-
rawValues: true,
11+
raw: true,
1212
})(validData, undefined, {
1313
fields,
1414
shouldUseNativeValidation,
@@ -77,4 +77,16 @@ describe('zodResolver', () => {
7777

7878
expect(result).toMatchSnapshot();
7979
});
80+
81+
it('should throw any error unrelated to Zod', async () => {
82+
const schemaWithCustomError = schema.refine(() => {
83+
throw Error('custom error');
84+
});
85+
const promise = zodResolver(schemaWithCustomError)(validData, undefined, {
86+
fields,
87+
shouldUseNativeValidation,
88+
});
89+
90+
await expect(promise).rejects.toThrow('custom error');
91+
});
8092
});

zod/src/types.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
FieldValues,
3-
ResolverResult,
4-
ResolverOptions,
5-
} from 'react-hook-form';
1+
import { FieldValues, ResolverResult, ResolverOptions } from 'react-hook-form';
62
import { z } from 'zod';
73

84
export type Resolver = <T extends z.Schema<any, any>>(
@@ -17,7 +13,7 @@ export type Resolver = <T extends z.Schema<any, any>>(
1713
* Return the raw input values rather than the parsed values.
1814
* @default false
1915
*/
20-
rawValues?: boolean;
16+
raw?: boolean;
2117
},
2218
) => <TFieldValues extends FieldValues, TContext>(
2319
values: TFieldValues,

0 commit comments

Comments
 (0)