diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5cf0e311..b4c0e5cd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,6 +28,9 @@ jobs: - name: Lint run: bun lint + + - name: Test + run: bun run test - name: TS run: bun lint:types diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff9f7ffc..f372dab9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Here is a quick guide to doing code contributions to the library. 4. If you've added a code that should be tested, ensure the test suite still passes. - > bun test + > bun run test 5. Try to write some unit tests to cover as much of your code as possible. diff --git a/arktype/src/__tests__/__snapshots__/arktype.ts.snap b/arktype/src/__tests__/__snapshots__/arktype.ts.snap index 51991b6c..4fea5e15 100644 --- a/arktype/src/__tests__/__snapshots__/arktype.ts.snap +++ b/arktype/src/__tests__/__snapshots__/arktype.ts.snap @@ -6,41 +6,41 @@ exports[`arktypeResolver > should return a single error from arktypeResolver whe "accessToken": { "message": "accessToken must be a number or a string (was missing)", "ref": undefined, - "type": "required", + "type": "", }, "birthYear": { "message": "birthYear must be a number (was a string)", "ref": undefined, - "type": "domain", + "type": "", }, "dateStr": { "message": "dateStr must be a Date (was missing)", "ref": undefined, - "type": "required", + "type": "", }, "email": { "message": "email must be an email address (was "")", "ref": { "name": "email", }, - "type": "pattern", + "type": "", }, "enabled": { "message": "enabled must be boolean (was missing)", "ref": undefined, - "type": "required", + "type": "", }, "like": [ { "id": { "message": "like[0].id must be a number (was a string)", "ref": undefined, - "type": "domain", + "type": "", }, "name": { "message": "like[0].name must be a string (was missing)", "ref": undefined, - "type": "required", + "type": "", }, }, ], @@ -49,24 +49,24 @@ exports[`arktypeResolver > should return a single error from arktypeResolver whe "ref": { "name": "password", }, - "type": "union", + "type": "", }, "repeatPassword": { "message": "repeatPassword must be a string (was missing)", "ref": undefined, - "type": "required", + "type": "", }, "tags": { "message": "tags must be an array (was missing)", "ref": undefined, - "type": "required", + "type": "", }, "username": { "message": "username must be a string (was missing)", "ref": { "name": "username", }, - "type": "required", + "type": "", }, }, "values": {}, diff --git a/arktype/src/__tests__/arktype.ts b/arktype/src/__tests__/arktype.ts index a235952a..4b010d3e 100644 --- a/arktype/src/__tests__/arktype.ts +++ b/arktype/src/__tests__/arktype.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { type } from 'arktype'; import { Resolver, useForm } from 'react-hook-form'; import { SubmitHandler } from 'react-hook-form'; @@ -51,9 +52,13 @@ describe('arktypeResolver', () => { it('should correctly infer the output type from a arktype schema for the handleSubmit function in useForm', () => { const schema = type({ id: 'number' }); - const form = useForm({ - resolver: arktypeResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: arktypeResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -67,9 +72,13 @@ describe('arktypeResolver', () => { it('should correctly infer the output type from a arktype schema with a transform for the handleSubmit function in useForm', () => { const schema = type({ id: type('string').pipe((s) => Number.parseInt(s)) }); - const form = useForm({ - resolver: arktypeResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: arktypeResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/bun.lock b/bun.lock index 3c54f718..eb54394a 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "@hookform/resolvers", diff --git a/computed-types/src/__tests__/computed-types.ts b/computed-types/src/__tests__/computed-types.ts index 8da5bcee..3e558692 100644 --- a/computed-types/src/__tests__/computed-types.ts +++ b/computed-types/src/__tests__/computed-types.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import Schema, { number } from 'computed-types'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { computedTypesResolver } from '..'; @@ -65,9 +66,13 @@ describe('computedTypesResolver', () => { it('should correctly infer the output type from a computedTypes schema for the handleSubmit function in useForm', () => { const schema = Schema({ id: number }); - const form = useForm({ - resolver: computedTypesResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: computedTypesResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -81,9 +86,13 @@ describe('computedTypesResolver', () => { it('should correctly infer the output type from a computedTypes schema with a transform for the handleSubmit function in useForm', () => { const schema = Schema({ id: number.transform((val) => String(val)) }); - const form = useForm({ - resolver: computedTypesResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: computedTypesResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/effect-ts/src/__tests__/effect-ts.ts b/effect-ts/src/__tests__/effect-ts.ts index 5aae9140..c43e5731 100644 --- a/effect-ts/src/__tests__/effect-ts.ts +++ b/effect-ts/src/__tests__/effect-ts.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { Schema } from 'effect'; import { Resolver, useForm } from 'react-hook-form'; import { SubmitHandler } from 'react-hook-form'; @@ -114,9 +115,13 @@ describe('effectTsResolver', () => { it('should correctly infer the output type from a effectTs schema for the handleSubmit function in useForm', () => { const schema = Schema.Struct({ id: Schema.Number }); - const form = useForm({ - resolver: effectTsResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: effectTsResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -133,9 +138,13 @@ describe('effectTsResolver', () => { }), }); - const form = useForm({ - resolver: effectTsResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: effectTsResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/io-ts/src/__tests__/io-ts.ts b/io-ts/src/__tests__/io-ts.ts index 115afa60..e2b240fa 100644 --- a/io-ts/src/__tests__/io-ts.ts +++ b/io-ts/src/__tests__/io-ts.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import * as t from 'io-ts'; import * as tt from 'io-ts-types'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; @@ -60,9 +61,13 @@ describe('ioTsResolver', () => { it('should correctly infer the output type from a io-ts schema for the handleSubmit function in useForm', () => { const schema = t.type({ id: t.number }); - const form = useForm({ - resolver: ioTsResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: ioTsResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -76,9 +81,13 @@ describe('ioTsResolver', () => { it('should correctly infer the output type from a io-ts schema with a transform for the handleSubmit function in useForm', () => { const schema = t.type({ id: tt.NumberFromString }); - const form = useForm({ - resolver: ioTsResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: ioTsResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/standard-schema/src/__tests__/standard-schema.ts b/standard-schema/src/__tests__/standard-schema.ts index b3c319d7..6ef87dc4 100644 --- a/standard-schema/src/__tests__/standard-schema.ts +++ b/standard-schema/src/__tests__/standard-schema.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { z } from 'zod/v3'; import { standardSchemaResolver } from '..'; @@ -113,13 +114,16 @@ describe('standardSchemaResolver', () => { it('should correctly infer the output type from a standardSchema schema for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number() }); - - const form = useForm({ - resolver: standardSchemaResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: standardSchemaResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -133,12 +137,16 @@ describe('standardSchemaResolver', () => { it('should correctly infer the output type from a standardSchema schema with a transform for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number().transform((val) => String(val)) }); - const form = useForm({ - resolver: standardSchemaResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: standardSchemaResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/superstruct/src/__tests__/superstruct.ts b/superstruct/src/__tests__/superstruct.ts index 07a45c15..66b65c31 100644 --- a/superstruct/src/__tests__/superstruct.ts +++ b/superstruct/src/__tests__/superstruct.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import * as s from 'superstruct'; import { superstructResolver } from '..'; @@ -18,8 +19,9 @@ describe('superstructResolver', () => { it('should return values from superstructResolver with coerced values', async () => { const result = await superstructResolver( s.object({ - id: s.coerce(s.number(), s.string(), (val) => String(val)), + id: s.coerce(s.string(), s.number(), (val) => String(val)), }), + { coerce: true }, )({ id: 1 }, undefined, { fields, shouldUseNativeValidation, @@ -64,9 +66,13 @@ describe('superstructResolver', () => { it('should correctly infer the output type from a superstruct schema for the handleSubmit function in useForm', () => { const schema = s.object({ id: s.number() }); - const form = useForm({ - resolver: superstructResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: superstructResolver(schema, {}), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -82,11 +88,19 @@ describe('superstructResolver', () => { id: s.coerce(s.string(), s.number(), (val) => String(val)), }); - const form = useForm({ - resolver: superstructResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + // With coerce, there is no way to infer the input type of the schema + resolver: superstructResolver<{ id: number }, unknown, { id: string }>( + schema, + { coerce: true }, + ), + }), + ); - expectTypeOf(form.watch('id')).toEqualTypeOf(); + expectTypeOf(form.watch('id')).toEqualTypeOf(); expectTypeOf(form.handleSubmit).parameter(0).toEqualTypeOf< SubmitHandler<{ diff --git a/superstruct/src/superstruct.ts b/superstruct/src/superstruct.ts index 755d2855..8b5df17f 100644 --- a/superstruct/src/superstruct.ts +++ b/superstruct/src/superstruct.ts @@ -13,6 +13,19 @@ function parseErrorSchema(error: StructError) { ); } +// This is required to correctly type the input of the returned function when coerce is true +// superstruct does not store the input type of a schema alongside it +// Infer gives the output type of the coercion +export function superstructResolver( + schema: Struct, + schemaOptions: Omit[2], 'coerce'> & { + coerce: true; + }, + resolverOptions?: { + raw?: boolean; + }, +): Resolver; + export function superstructResolver( schema: Struct, schemaOptions?: Parameters[2], diff --git a/typanion/src/__tests__/typanion.ts b/typanion/src/__tests__/typanion.ts index d72d127e..524d607d 100644 --- a/typanion/src/__tests__/typanion.ts +++ b/typanion/src/__tests__/typanion.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { SubmitHandler } from 'react-hook-form'; import { useForm } from 'react-hook-form'; import { Resolver } from 'react-hook-form'; @@ -51,9 +52,13 @@ describe('typanionResolver', () => { it('should correctly infer the output type from a typanion schema for the handleSubmit function in useForm', () => { const schema = t.isObject({ id: t.isNumber() }); - const form = useForm({ - resolver: typanionResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typanionResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/typebox/src/__tests__/typebox.ts b/typebox/src/__tests__/typebox.ts index 7fb7dfa3..05229ccc 100644 --- a/typebox/src/__tests__/typebox.ts +++ b/typebox/src/__tests__/typebox.ts @@ -1,5 +1,6 @@ import { Type } from '@sinclair/typebox'; import { TypeCompiler } from '@sinclair/typebox/compiler'; +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { typeboxResolver } from '..'; import { fields, invalidData, schema, validData } from './__fixtures__/data'; @@ -72,12 +73,16 @@ describe('typeboxResolver', () => { it('should correctly infer the output type from a typebox schema for the handleSubmit function in useForm', () => { const schema = Type.Object({ id: Type.Number() }); - const form = useForm({ - resolver: typeboxResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typeboxResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -91,12 +96,16 @@ describe('typeboxResolver', () => { it('should correctly infer the output type from a typebox schema with TypeCompiler for the handleSubmit function in useForm', () => { const typecheck = TypeCompiler.Compile(Type.Object({ id: Type.Number() })); - const form = useForm({ - resolver: typeboxResolver(typecheck), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typeboxResolver(typecheck), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -114,12 +123,16 @@ describe('typeboxResolver', () => { .Encode((v) => Number.parseInt(v)), }); - const form = useForm({ - resolver: typeboxResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typeboxResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/typeschema/src/__tests__/typeschema.ts b/typeschema/src/__tests__/typeschema.ts index a60ab076..979057dc 100644 --- a/typeschema/src/__tests__/typeschema.ts +++ b/typeschema/src/__tests__/typeschema.ts @@ -1,4 +1,4 @@ -import * as typeschema from '@typeschema/main'; +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { z } from 'zod/v3'; import { typeschemaResolver } from '..'; @@ -13,7 +13,7 @@ vi.mock('@typeschema/main', async (importOriginal) => { describe('typeschemaResolver', () => { it('should return values from typeschemaResolver when validation pass & raw=true', async () => { - const validateSpy = vi.spyOn(typeschema, 'validate'); + const validateSpy = vi.spyOn(schema['~standard'], 'validate'); const result = await typeschemaResolver(schema, undefined, { raw: true })( validData, @@ -26,7 +26,7 @@ describe('typeschemaResolver', () => { }); it('should return parsed values from typeschemaResolver when validation pass', async () => { - const validateSpy = vi.spyOn(typeschema, 'validate'); + const validateSpy = vi.spyOn(schema['~standard'], 'validate'); const result = await typeschemaResolver(schema)(validData, undefined, { fields, @@ -110,12 +110,16 @@ describe('typeschemaResolver', () => { it('should correctly infer the output type from a typeschema schema for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number() }); - const form = useForm({ - resolver: typeschemaResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typeschemaResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -129,12 +133,16 @@ describe('typeschemaResolver', () => { it('should correctly infer the output type from a typeschema schema with a transform for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number().transform((val) => String(val)) }); - const form = useForm({ - resolver: typeschemaResolver(schema), - defaultValues: { - id: 3, - }, - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: typeschemaResolver(schema), + defaultValues: { + id: 3, + }, + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/typeschema/src/typeschema.ts b/typeschema/src/typeschema.ts index bba859bb..75b9d6be 100644 --- a/typeschema/src/typeschema.ts +++ b/typeschema/src/typeschema.ts @@ -12,12 +12,14 @@ const parseErrorSchema = ( typeschemaErrors: readonly StandardSchemaV1.Issue[], validateAllFieldCriteria: boolean, ): FieldErrors => { - const schemaErrors = Object.assign([], typeschemaErrors); + // Need to pass generics so that the array isn't typed as "never[]" + const schemaErrors = Object.assign( + [] as typeof typeschemaErrors, + typeschemaErrors, + ); const errors: Record = {}; - for (; schemaErrors.length; ) { - const error = typeschemaErrors[0]; - + for (const error of schemaErrors) { if (!error.path) { continue; } @@ -41,8 +43,6 @@ const parseErrorSchema = ( : error.message, ) as FieldError; } - - schemaErrors.shift(); } return errors; diff --git a/valibot/src/__tests__/valibot.ts b/valibot/src/__tests__/valibot.ts index 1e8e4a18..ad8981be 100644 --- a/valibot/src/__tests__/valibot.ts +++ b/valibot/src/__tests__/valibot.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { SubmitHandler } from 'react-hook-form'; import { useForm } from 'react-hook-form'; import { Resolver } from 'react-hook-form'; @@ -171,9 +172,13 @@ describe('valibotResolver', () => { it('should correctly infer the output type from a valibot schema for the handleSubmit function in useForm', () => { const schema = v.object({ id: v.number() }); - const form = useForm({ - resolver: valibotResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: valibotResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -192,9 +197,13 @@ describe('valibotResolver', () => { ), }); - const form = useForm({ - resolver: valibotResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: valibotResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/vine/src/__tests__/vine.ts b/vine/src/__tests__/vine.ts index 8d7fff7c..addf150c 100644 --- a/vine/src/__tests__/vine.ts +++ b/vine/src/__tests__/vine.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import vine from '@vinejs/vine'; import { Resolver, useForm } from 'react-hook-form'; import { SubmitHandler } from 'react-hook-form'; @@ -87,9 +88,13 @@ describe('vineResolver', () => { it('should correctly infer the output type from a vine schema for the handleSubmit function in useForm', () => { const schema = vine.compile(vine.object({ id: vine.number() })); - const form = useForm({ - resolver: vineResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: vineResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -107,9 +112,13 @@ describe('vineResolver', () => { }), ); - const form = useForm({ - resolver: vineResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: vineResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/vitest.config.mts b/vitest.config.mts index 0e8751c1..e8812240 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -13,8 +13,15 @@ export default defineConfig({ environment: 'jsdom', setupFiles: ['./tests/setup.ts'], include: ['**/__tests__/**/*.+(js|jsx|ts|tsx)'], - exclude: ['**/node_modules/**', '**/__fixtures__/**', '/\\.'], + exclude: ['**/node_modules/**', '**/__fixtures__/**'], clearMocks: true, restoreMocks: true, + server: { + deps: { + // Needed to spy on "zod/v4/core" parse method without getting the error + // TypeError: Cannot redefine property: parse + inline: ['z'], + }, + }, }, }); diff --git a/yup/src/__tests__/yup.ts b/yup/src/__tests__/yup.ts index fb0ff32b..246793ed 100644 --- a/yup/src/__tests__/yup.ts +++ b/yup/src/__tests__/yup.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { type Resolver, type SubmitHandler, useForm } from 'react-hook-form'; /* eslint-disable no-console, @typescript-eslint/ban-ts-comment */ import * as yup from 'yup'; @@ -248,9 +249,13 @@ describe('yupResolver', () => { it('should correctly infer the output type from a yup schema for the handleSubmit function in useForm', () => { const schema = yup.object({ id: yup.number().required() }); - const form = useForm({ - resolver: yupResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: yupResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -269,9 +274,13 @@ describe('yupResolver', () => { .transform((val) => String(val)), }); - const form = useForm({ - resolver: yupResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: yupResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/zod/src/__tests__/__snapshots__/zod-v3.ts.snap b/zod/src/__tests__/__snapshots__/zod-v3.ts.snap new file mode 100644 index 00000000..169a9bfe --- /dev/null +++ b/zod/src/__tests__/__snapshots__/zod-v3.ts.snap @@ -0,0 +1,430 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`zodResolver > should return a single error from zodResolver when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "birthYear": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid email", + "ref": { + "name": "email", + }, + "type": "invalid_string", + }, + "enabled": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_string", + }, + "repeatPassword": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_string", + }, + "username": { + "message": "Required", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return a single error from zodResolver with \`mode: sync\` when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "birthYear": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid email", + "ref": { + "name": "email", + }, + "type": "invalid_string", + }, + "enabled": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_string", + }, + "repeatPassword": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_string", + }, + "username": { + "message": "Required", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Required", + "Required", + ], + "invalid_union": "Invalid input", + }, + }, + "birthYear": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Expected number, received string", + }, + }, + "dateStr": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "email": { + "message": "Invalid email", + "ref": { + "name": "email", + }, + "type": "invalid_string", + "types": { + "invalid_string": "Invalid email", + }, + }, + "enabled": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "like": [ + { + "id": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Expected number, received string", + }, + }, + "name": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_string", + "types": { + "invalid_string": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "tags": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_string", + "types": { + "invalid_string": "Custom error url", + }, + }, + "username": { + "message": "Required", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Required", + "Required", + ], + "invalid_union": "Invalid input", + }, + }, + "birthYear": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Expected number, received string", + }, + }, + "dateStr": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "email": { + "message": "Invalid email", + "ref": { + "name": "email", + }, + "type": "invalid_string", + "types": { + "invalid_string": "Invalid email", + }, + }, + "enabled": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "like": [ + { + "id": { + "message": "Expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Expected number, received string", + }, + }, + "name": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_string", + "types": { + "invalid_string": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "tags": { + "message": "Required", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_string", + "types": { + "invalid_string": "Custom error url", + }, + }, + "username": { + "message": "Required", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Required", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return parsed values from zodResolver with \`mode: sync\` when validation pass 1`] = ` +{ + "errors": {}, + "values": { + "accessToken": "accessToken", + "birthYear": 2000, + "dateStr": 2020-01-01T00:00:00.000Z, + "email": "john@doe.com", + "enabled": true, + "like": [ + { + "id": 1, + "name": "name", + }, + ], + "password": "Password123_", + "repeatPassword": "Password123_", + "tags": [ + "tag1", + "tag2", + ], + "url": "https://react-hook-form.com/", + "username": "Doe", + }, +} +`; diff --git a/zod/src/__tests__/__snapshots__/zod-v4-mini.ts.snap b/zod/src/__tests__/__snapshots__/zod-v4-mini.ts.snap new file mode 100644 index 00000000..4788e7a3 --- /dev/null +++ b/zod/src/__tests__/__snapshots__/zod-v4-mini.ts.snap @@ -0,0 +1,472 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`zodResolver > should return a single error from zodResolver when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "auth": { + "type": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_union", + }, + }, + "birthYear": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid input", + "ref": { + "name": "email", + }, + "type": "invalid_format", + }, + "enabled": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + }, + "repeatPassword": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + }, + "username": { + "message": "Invalid input", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return a single error from zodResolver with \`mode: sync\` when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "auth": { + "type": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_union", + }, + }, + "birthYear": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid input", + "ref": { + "name": "email", + }, + "type": "invalid_format", + }, + "enabled": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + }, + "repeatPassword": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + }, + "username": { + "message": "Invalid input", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Invalid input", + "Invalid input", + ], + "invalid_union": "Invalid input", + }, + }, + "auth": { + "type": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_union", + "types": { + "invalid_union": "Invalid input", + }, + }, + }, + "birthYear": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "dateStr": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "email": { + "message": "Invalid input", + "ref": { + "name": "email", + }, + "type": "invalid_format", + "types": { + "invalid_format": "Invalid input", + }, + }, + "enabled": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "like": [ + { + "id": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "name": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + "types": { + "invalid_format": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "tags": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + "types": { + "invalid_format": "Custom error url", + "invalid_union": "Invalid input", + "invalid_value": "Invalid input", + }, + }, + "username": { + "message": "Invalid input", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Invalid input", + "Invalid input", + ], + "invalid_union": "Invalid input", + }, + }, + "auth": { + "type": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_union", + "types": { + "invalid_union": "Invalid input", + }, + }, + }, + "birthYear": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "dateStr": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "email": { + "message": "Invalid input", + "ref": { + "name": "email", + }, + "type": "invalid_format", + "types": { + "invalid_format": "Invalid input", + }, + }, + "enabled": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "like": [ + { + "id": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "name": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + "types": { + "invalid_format": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "tags": { + "message": "Invalid input", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + "types": { + "invalid_format": "Custom error url", + "invalid_union": "Invalid input", + "invalid_value": "Invalid input", + }, + }, + "username": { + "message": "Invalid input", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return parsed values from zodResolver with \`mode: sync\` when validation pass 1`] = ` +{ + "errors": {}, + "values": { + "accessToken": "accessToken", + "auth": { + "passwordHash": "hash", + "type": "registered", + }, + "birthYear": 2000, + "dateStr": 2020-01-01T00:00:00.000Z, + "email": "john@doe.com", + "enabled": true, + "like": [ + { + "id": 1, + "name": "name", + }, + ], + "password": "Password123_", + "repeatPassword": "Password123_", + "tags": [ + "tag1", + "tag2", + ], + "url": "https://react-hook-form.com/", + "username": "Doe", + }, +} +`; diff --git a/zod/src/__tests__/__snapshots__/zod-v4.ts.snap b/zod/src/__tests__/__snapshots__/zod-v4.ts.snap new file mode 100644 index 00000000..c2c74e71 --- /dev/null +++ b/zod/src/__tests__/__snapshots__/zod-v4.ts.snap @@ -0,0 +1,434 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`zodResolver > should return a single error from zodResolver when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "birthYear": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid email address", + "ref": { + "name": "email", + }, + "type": "invalid_format", + }, + "enabled": { + "message": "Invalid input: expected boolean, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + }, + "repeatPassword": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Invalid input: expected array, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + }, + "username": { + "message": "Invalid input: expected string, received undefined", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return a single error from zodResolver with \`mode: sync\` when validation fails 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "birthYear": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "dateStr": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "email": { + "message": "Invalid email address", + "ref": { + "name": "email", + }, + "type": "invalid_format", + }, + "enabled": { + "message": "Invalid input: expected boolean, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "like": [ + { + "id": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + }, + "name": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + }, + "repeatPassword": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "tags": { + "message": "Invalid input: expected array, received undefined", + "ref": undefined, + "type": "invalid_type", + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + }, + "username": { + "message": "Invalid input: expected string, received undefined", + "ref": { + "name": "username", + }, + "type": "invalid_type", + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Invalid input: expected string, received undefined", + "Invalid input: expected number, received undefined", + ], + "invalid_union": "Invalid input", + }, + }, + "birthYear": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected number, received string", + }, + }, + "dateStr": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + "email": { + "message": "Invalid email address", + "ref": { + "name": "email", + }, + "type": "invalid_format", + "types": { + "invalid_format": "Invalid email address", + }, + }, + "enabled": { + "message": "Invalid input: expected boolean, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected boolean, received undefined", + }, + }, + "like": [ + { + "id": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected number, received string", + }, + }, + "name": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + "types": { + "invalid_format": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + "tags": { + "message": "Invalid input: expected array, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected array, received undefined", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + "types": { + "invalid_format": "Custom error url", + "invalid_union": "Invalid input", + "invalid_value": "Invalid input: expected """, + }, + }, + "username": { + "message": "Invalid input: expected string, received undefined", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = ` +{ + "errors": { + "accessToken": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": [ + "Invalid input: expected string, received undefined", + "Invalid input: expected number, received undefined", + ], + "invalid_union": "Invalid input", + }, + }, + "birthYear": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected number, received string", + }, + }, + "dateStr": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + "email": { + "message": "Invalid email address", + "ref": { + "name": "email", + }, + "type": "invalid_format", + "types": { + "invalid_format": "Invalid email address", + }, + }, + "enabled": { + "message": "Invalid input: expected boolean, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected boolean, received undefined", + }, + }, + "like": [ + { + "id": { + "message": "Invalid input: expected number, received string", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected number, received string", + }, + }, + "name": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + }, + ], + "password": { + "message": "One uppercase character", + "ref": { + "name": "password", + }, + "type": "invalid_format", + "types": { + "invalid_format": [ + "One uppercase character", + "One lowercase character", + "One number", + ], + "too_small": "Must be at least 8 characters in length", + }, + }, + "repeatPassword": { + "message": "Invalid input: expected string, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + "tags": { + "message": "Invalid input: expected array, received undefined", + "ref": undefined, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected array, received undefined", + }, + }, + "url": { + "message": "Custom error url", + "ref": undefined, + "type": "invalid_format", + "types": { + "invalid_format": "Custom error url", + "invalid_union": "Invalid input", + "invalid_value": "Invalid input: expected """, + }, + }, + "username": { + "message": "Invalid input: expected string, received undefined", + "ref": { + "name": "username", + }, + "type": "invalid_type", + "types": { + "invalid_type": "Invalid input: expected string, received undefined", + }, + }, + }, + "values": {}, +} +`; + +exports[`zodResolver > should return parsed values from zodResolver with \`mode: sync\` when validation pass 1`] = ` +{ + "errors": {}, + "values": { + "accessToken": "accessToken", + "birthYear": 2000, + "dateStr": 2020-01-01T00:00:00.000Z, + "email": "john@doe.com", + "enabled": true, + "like": [ + { + "id": 1, + "name": "name", + }, + ], + "password": "Password123_", + "repeatPassword": "Password123_", + "tags": [ + "tag1", + "tag2", + ], + "url": "https://react-hook-form.com/", + "username": "Doe", + }, +} +`; diff --git a/zod/src/__tests__/zod-v3.ts b/zod/src/__tests__/zod-v3.ts index 8e040ba6..db45918b 100644 --- a/zod/src/__tests__/zod-v3.ts +++ b/zod/src/__tests__/zod-v3.ts @@ -1,3 +1,4 @@ +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { z } from 'zod/v3'; import { zodResolver } from '..'; @@ -147,9 +148,13 @@ describe('zodResolver', () => { it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number() }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -163,9 +168,13 @@ describe('zodResolver', () => { it('should correctly infer the output type from a Zod schema with a transform for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number().transform((val) => String(val)) }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/zod/src/__tests__/zod-v4-mini.ts b/zod/src/__tests__/zod-v4-mini.ts index 54c5681c..2b10e6de 100644 --- a/zod/src/__tests__/zod-v4-mini.ts +++ b/zod/src/__tests__/zod-v4-mini.ts @@ -1,5 +1,7 @@ +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { z } from 'zod/v4-mini'; +import * as v4Core from 'zod/v4/core'; import { zodResolver } from '..'; import { fields, @@ -12,7 +14,7 @@ const shouldUseNativeValidation = false; describe('zodResolver', () => { it('should return values from zodResolver when validation pass & raw=true', async () => { - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { raw: true, @@ -28,8 +30,8 @@ describe('zodResolver', () => { }); it('should return parsed values from zodResolver with `mode: sync` when validation pass', async () => { - const parseSpy = vi.spyOn(schema, 'parse'); - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseSpy = vi.spyOn(v4Core, 'parse'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { mode: 'sync', @@ -50,8 +52,8 @@ describe('zodResolver', () => { }); it('should return a single error from zodResolver with `mode: sync` when validation fails', async () => { - const parseSpy = vi.spyOn(schema, 'parse'); - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseSpy = vi.spyOn(v4Core, 'parse'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { mode: 'sync', @@ -146,9 +148,13 @@ describe('zodResolver', () => { it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number() }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -167,9 +173,13 @@ describe('zodResolver', () => { ), }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); diff --git a/zod/src/__tests__/zod-v4.ts b/zod/src/__tests__/zod-v4.ts index 0a043bc0..7aa2c456 100644 --- a/zod/src/__tests__/zod-v4.ts +++ b/zod/src/__tests__/zod-v4.ts @@ -1,5 +1,7 @@ +import { renderHook } from '@testing-library/react'; import { Resolver, SubmitHandler, useForm } from 'react-hook-form'; import { z } from 'zod/v4'; +import * as v4Core from 'zod/v4/core'; import { zodResolver } from '..'; import { fields, invalidData, schema, validData } from './__fixtures__/data-v4'; @@ -7,7 +9,7 @@ const shouldUseNativeValidation = false; describe('zodResolver', () => { it('should return values from zodResolver when validation pass & raw=true', async () => { - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { raw: true, @@ -21,8 +23,8 @@ describe('zodResolver', () => { }); it('should return parsed values from zodResolver with `mode: sync` when validation pass', async () => { - const parseSpy = vi.spyOn(schema, 'parse'); - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseSpy = vi.spyOn(v4Core, 'parse'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { mode: 'sync', @@ -44,8 +46,8 @@ describe('zodResolver', () => { }); it('should return a single error from zodResolver with `mode: sync` when validation fails', async () => { - const parseSpy = vi.spyOn(schema, 'parse'); - const parseAsyncSpy = vi.spyOn(schema, 'parseAsync'); + const parseSpy = vi.spyOn(v4Core, 'parse'); + const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync'); const result = await zodResolver(schema, undefined, { mode: 'sync', @@ -145,9 +147,13 @@ describe('zodResolver', () => { it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number() }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf(); @@ -161,9 +167,13 @@ describe('zodResolver', () => { it('should correctly infer the output type from a Zod schema with a transform for the handleSubmit function in useForm', () => { const schema = z.object({ id: z.number().transform((val) => String(val)) }); - const form = useForm({ - resolver: zodResolver(schema), - }); + const { + result: { current: form }, + } = renderHook(() => + useForm({ + resolver: zodResolver(schema), + }), + ); expectTypeOf(form.watch('id')).toEqualTypeOf();