Skip to content

Commit 39731b3

Browse files
authored
Support Yup ^0.32.0 (#92)
* test: restoreMocks: true * chore: update yup * chore: update Yup * chore: use AnyObjectSchema instead of ObjectSchema * revert: test description * chore: support last yup version * test: update tests * chore: improve typings
1 parent 76c68cc commit 39731b3

File tree

6 files changed

+144
-92
lines changed

6 files changed

+144
-92
lines changed

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
tsconfig: 'tsconfig.jest.json',
99
},
1010
},
11+
restoreMocks: true,
1112
testMatch: ['**/?(*.)+(spec|test).ts?(x)'],
1213
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'],
1314
moduleFileExtensions: ['ts', 'tsx', 'js'],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@
8181
"rollup-plugin-typescript2": "^0.29.0",
8282
"superstruct": "^0.13.1",
8383
"ts-jest": "^26.4.4",
84+
"yup": "^0.32.8",
8485
"typescript": "^4.1.3",
8586
"vest": "^2.2.3",
86-
"yup": "^0.31.0",
8787
"zod": "^1.11.11"
8888
},
8989
"peerDependencies": {

src/__snapshots__/yup.test.ts.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,15 @@ Object {
105105
"values": Object {},
106106
}
107107
`;
108+
109+
exports[`yupResolver should pass down the yup context 1`] = `
110+
Object {
111+
"errors": Object {
112+
"name": Object {
113+
"message": "name must be at least 6 characters",
114+
"type": "min",
115+
},
116+
},
117+
"values": Object {},
118+
}
119+
`;

src/yup.test.ts

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable no-console */
1+
/* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
22
import * as yup from 'yup';
33
import { yupResolver } from './yup';
44

@@ -42,7 +42,7 @@ const errors = {
4242
],
4343
};
4444

45-
const schema = yup.object().shape({
45+
const schema = yup.object({
4646
name: yup.string().required(),
4747
age: yup.number().required().positive().integer(),
4848
email: yup.string().email(),
@@ -72,42 +72,43 @@ describe('yupResolver', () => {
7272
it('should get values', async () => {
7373
const data = {
7474
name: 'jimmy',
75-
age: '24',
75+
age: 24,
76+
7677
password: '[}tehk6Uor',
77-
createdOn: '2014-09-23T19:25:25Z',
78-
foo: [{ yup: true }],
78+
website: 'https://react-hook-form.com/',
79+
createdOn: new Date('2014-09-23T19:25:25Z'),
80+
foo: [{ loose: true }],
7981
};
8082
expect(await yupResolver(schema)(data)).toEqual({
8183
errors: {},
82-
values: {
83-
name: 'jimmy',
84-
age: 24,
85-
password: '[}tehk6Uor',
86-
foo: [{ yup: true }],
87-
createdOn: new Date('2014-09-23T19:25:25Z'),
88-
},
84+
values: data,
8985
});
9086
});
9187

9288
it('should pass down the yup context', async () => {
9389
const data = { name: 'eric' };
9490
const context = { min: true };
95-
const schemaWithContext = yup.object().shape({
91+
const schemaWithContext = yup.object({
9692
name: yup
9793
.string()
9894
.required()
9995
.when('$min', (min: boolean, schema: yup.StringSchema) => {
10096
return min ? schema.min(6) : schema;
10197
}),
10298
});
103-
schemaWithContext.validate = jest.fn().mockResolvedValue({});
104-
await yupResolver(schemaWithContext)(data, context);
105-
expect(schemaWithContext.validate).toHaveBeenCalled();
106-
expect(schemaWithContext.validate).toHaveBeenCalledWith(data, {
107-
abortEarly: false,
108-
context,
109-
});
110-
(schemaWithContext.validate as jest.Mock).mockClear();
99+
100+
const schemaSpyValidate = jest.spyOn(schemaWithContext, 'validate');
101+
102+
const output = await yupResolver(schemaWithContext)(data, context);
103+
expect(schemaSpyValidate).toHaveBeenCalledTimes(1);
104+
expect(schemaSpyValidate).toHaveBeenCalledWith(
105+
data,
106+
expect.objectContaining({
107+
abortEarly: false,
108+
context,
109+
}),
110+
);
111+
expect(output).toMatchSnapshot();
111112
});
112113

113114
describe('errors', () => {
@@ -119,26 +120,33 @@ describe('yupResolver', () => {
119120
createdOn: null,
120121
foo: [{ loose: null }],
121122
};
122-
const resolve = await yupResolver(schema)(data, {}, true);
123-
expect(resolve).toMatchSnapshot();
124-
expect(resolve.errors['foo'][0]['loose']).toBeDefined();
125-
expect(resolve.errors['foo'][0]['loose'].types).toMatchInlineSnapshot(`
123+
124+
const output = await yupResolver(schema)(
125+
// @ts-expect-error
126+
data,
127+
{},
128+
true,
129+
);
130+
expect(output).toMatchSnapshot();
131+
expect(output.errors['foo']?.[0]?.['loose']).toBeDefined();
132+
expect(output.errors['foo']?.[0]?.['loose']?.types)
133+
.toMatchInlineSnapshot(`
126134
Object {
127135
"typeError": "foo[0].loose must be a \`boolean\` type, but the final value was: \`null\`.
128136
If \\"null\\" is intended as an empty value be sure to mark the schema as \`.nullable()\`",
129137
}
130138
`);
131-
expect(resolve.errors.age.types).toMatchInlineSnapshot(`
139+
expect(output.errors.age?.types).toMatchInlineSnapshot(`
132140
Object {
133141
"typeError": "age must be a \`number\` type, but the final value was: \`NaN\` (cast from the value \`\\"test\\"\`).",
134142
}
135143
`);
136-
expect(resolve.errors.createdOn.types).toMatchInlineSnapshot(`
144+
expect(output.errors.createdOn?.types).toMatchInlineSnapshot(`
137145
Object {
138146
"typeError": "createdOn must be a \`date\` type, but the final value was: \`Invalid Date\`.",
139147
}
140148
`);
141-
expect(resolve.errors.password.types).toMatchInlineSnapshot(`
149+
expect(output.errors.password?.types).toMatchInlineSnapshot(`
142150
Object {
143151
"matches": Array [
144152
"Lowercase",
@@ -159,12 +167,13 @@ describe('yupResolver', () => {
159167
createdOn: null,
160168
foo: [{ loose: null }],
161169
};
162-
const resolve = await yupResolver(schema)(data);
163-
expect(await yupResolver(schema)(data)).toMatchSnapshot();
164-
expect(resolve.errors['foo[0].loose']).toBeUndefined();
165-
expect(resolve.errors.age.types).toBeUndefined();
166-
expect(resolve.errors.createdOn.types).toBeUndefined();
167-
expect(resolve.errors.password.types).toBeUndefined();
170+
171+
// @ts-expect-error
172+
const output = await yupResolver(schema)(data);
173+
expect(output).toMatchSnapshot();
174+
expect(output.errors.age?.types).toBeUndefined();
175+
expect(output.errors.createdOn?.types).toBeUndefined();
176+
expect(output.errors.password?.types).toBeUndefined();
168177
});
169178

170179
it('should get error if yup errors has no inner errors', async () => {
@@ -174,10 +183,12 @@ describe('yupResolver', () => {
174183
createdOn: null,
175184
foo: [{ loose: null }],
176185
};
177-
const resolve = await yupResolver(schema, {
186+
const output = await yupResolver(schema, {
178187
abortEarly: true,
179-
})(data);
180-
expect(resolve.errors).toMatchInlineSnapshot(`
188+
// @ts-expect-error
189+
})(data, undefined, true);
190+
191+
expect(output.errors).toMatchInlineSnapshot(`
181192
Object {
182193
"createdOn": Object {
183194
"message": "createdOn must be a \`date\` type, but the final value was: \`Invalid Date\`.",
@@ -192,35 +203,35 @@ describe('yupResolver', () => {
192203
const schemaWithContext = yup.object().shape({
193204
name: yup.string().required(),
194205
});
195-
schemaWithContext.validate = jest.fn().mockRejectedValue({
206+
207+
jest.spyOn(schemaWithContext, 'validate').mockRejectedValueOnce({
196208
inner: [{ path: '', message: 'error1', type: 'required' }],
197-
} as yup.ValidationError);
198-
const result = await yupResolver(schemaWithContext)(data);
199-
expect(result).toMatchSnapshot();
209+
});
210+
211+
// @ts-expect-error
212+
const output = await yupResolver(schemaWithContext)(data);
213+
expect(output).toMatchSnapshot();
200214
});
201215
});
202216
});
203217

204218
describe('validateWithSchema', () => {
205219
it('should return undefined when no error reported', async () => {
206-
expect(
207-
await yupResolver({
208-
validate: () => {
209-
throw errors;
210-
},
211-
} as any)({}),
212-
).toMatchSnapshot();
220+
const schema = yup.object();
221+
jest.spyOn(schema, 'validate').mockRejectedValueOnce(errors);
222+
223+
expect(await yupResolver(schema)({})).toMatchSnapshot();
213224
});
214225

215226
it('should return empty object when validate pass', async () => {
216-
expect(
217-
await yupResolver({
218-
validate: () => new Promise((resolve) => resolve(undefined)),
219-
} as any)({}),
220-
).toEqual({
221-
errors: {},
222-
values: undefined,
223-
});
227+
const schema = yup.object();
228+
229+
expect(await yupResolver(schema)({})).toMatchInlineSnapshot(`
230+
Object {
231+
"errors": Object {},
232+
"values": Object {},
233+
}
234+
`);
224235
});
225236

226237
it('should return an error based on the user context', async () => {
@@ -233,6 +244,8 @@ describe('validateWithSchema', () => {
233244
return min ? schema.min(6) : schema;
234245
}),
235246
});
247+
248+
// @ts-expect-error
236249
expect(await yupResolver(schemaWithContext)(data, { min: true }))
237250
.toMatchInlineSnapshot(`
238251
Object {
@@ -248,29 +261,23 @@ describe('validateWithSchema', () => {
248261
});
249262

250263
it('should show a warning log if yup context is used instead only on dev environment', async () => {
251-
console.warn = jest.fn();
264+
jest.spyOn(console, 'warn').mockImplementation(jest.fn);
252265
process.env.NODE_ENV = 'development';
253-
await yupResolver(
254-
{} as any,
255-
{ context: { noContext: true } } as yup.ValidateOptions,
256-
)({});
266+
267+
await yupResolver(yup.object(), { context: { noContext: true } })({});
257268
expect(console.warn).toHaveBeenCalledWith(
258269
"You should not used the yup options context. Please, use the 'useForm' context object instead",
259270
);
260271
process.env.NODE_ENV = 'test';
261-
(console.warn as jest.Mock).mockClear();
262272
});
263273

264274
it('should not show warning log if yup context is used instead only on production environment', async () => {
265-
console.warn = jest.fn();
275+
jest.spyOn(console, 'warn').mockImplementation(jest.fn);
266276
process.env.NODE_ENV = 'production';
267-
await yupResolver(
268-
{} as any,
269-
{ context: { noContext: true } } as yup.ValidateOptions,
270-
)({});
277+
278+
await yupResolver(yup.object(), { context: { noContext: true } })({});
271279
expect(console.warn).not.toHaveBeenCalled();
272280
process.env.NODE_ENV = 'test';
273-
(console.warn as jest.Mock).mockClear();
274281
});
275282

276283
it('should return correct error message with using yup.test', async () => {
@@ -280,9 +287,11 @@ describe('validateWithSchema', () => {
280287
name: yup.string(),
281288
email: yup.string(),
282289
})
283-
.test('name', 'Email or name are required', function (value) {
284-
return value && (value.name || value.email);
285-
}),
290+
.test(
291+
'name',
292+
'Email or name are required',
293+
(value) => !!(value && (value.name || value.email)),
294+
),
286295
)({ name: '', email: '' });
287296

288297
expect(output).toEqual({

0 commit comments

Comments
 (0)