From 3903da3bd6db7bcf5c1d3a0e8663f1578a2078bd Mon Sep 17 00:00:00 2001 From: Christopher Hlubek Date: Wed, 6 Jul 2022 20:55:03 +0200 Subject: [PATCH] Fix nested schema with computed-types --- computed-types/src/__tests__/Form.tsx | 9 +++++++ .../src/__tests__/__fixtures__/data.ts | 14 +++++++++++ .../__snapshots__/computed-types.ts.snap | 25 ++++++++++++++++--- computed-types/src/computed-types.ts | 14 +++-------- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/computed-types/src/__tests__/Form.tsx b/computed-types/src/__tests__/Form.tsx index dbe31c5b..98a4822b 100644 --- a/computed-types/src/__tests__/Form.tsx +++ b/computed-types/src/__tests__/Form.tsx @@ -8,6 +8,9 @@ import { computedTypesResolver } from '..'; const schema = Schema({ username: string.min(2).error('username field is required'), password: string.min(2).error('password field is required'), + address: Schema({ + zipCode: string.min(5).max(5).error('zipCode field is required'), + }), }); type FormData = Type & { unusedProperty: string }; @@ -33,6 +36,11 @@ function TestComponent({ onSubmit }: Props) { {errors.password && {errors.password.message}} + + {errors.address?.zipCode && ( + {errors.address.zipCode.message} + )} + ); @@ -50,5 +58,6 @@ test("form's validation with computed-types and TypeScript's integration", async expect(screen.getByText(/username field is required/i)).toBeInTheDocument(); expect(screen.getByText(/password field is required/i)).toBeInTheDocument(); + expect(screen.getByText(/zipCode field is required/i)).toBeInTheDocument(); expect(handleSubmit).not.toHaveBeenCalled(); }); diff --git a/computed-types/src/__tests__/__fixtures__/data.ts b/computed-types/src/__tests__/__fixtures__/data.ts index 7ba69f6d..afe25a89 100644 --- a/computed-types/src/__tests__/__fixtures__/data.ts +++ b/computed-types/src/__tests__/__fixtures__/data.ts @@ -26,6 +26,12 @@ export const schema = Schema({ name: string.min(4).max(4), }) .optional(), + address: Schema({ + city: string.min(3, 'Is required'), + zipCode: string + .min(5, 'Must be 5 characters long') + .max(5, 'Must be 5 characters long'), + }), }); export const validData: Type = { @@ -43,6 +49,10 @@ export const validData: Type = { name: 'name', }, ], + address: { + city: 'Awesome city', + zipCode: '12345', + }, }; export const invalidData = { @@ -50,6 +60,10 @@ export const invalidData = { email: '', birthYear: 'birthYear', like: [{ id: 'z' }], + address: { + city: '', + zipCode: '123', + }, }; export const fields: Record = { diff --git a/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap b/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap index 94d87a95..30d22d1d 100644 --- a/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap +++ b/computed-types/src/__tests__/__snapshots__/computed-types.ts.snap @@ -3,6 +3,18 @@ exports[`computedTypesResolver should return a single error from computedTypesResolver when validation fails 1`] = ` Object { "errors": Object { + "address": Object { + "city": Object { + "message": "Is required", + "ref": undefined, + "type": "ValidationError", + }, + "zipCode": Object { + "message": "Must be 5 characters long", + "ref": undefined, + "type": "ValidationError", + }, + }, "birthYear": Object { "message": "Expect value to be \\"number\\"", "ref": undefined, @@ -21,9 +33,16 @@ Object { "type": "ValidationError", }, "like": Object { - "message": "Expect value to be \\"string\\"", - "ref": undefined, - "type": "ValidationError", + "id": Object { + "message": "Expect value to be \\"number\\"", + "ref": undefined, + "type": "ValidationError", + }, + "name": Object { + "message": "Expect value to be \\"string\\"", + "ref": undefined, + "type": "ValidationError", + }, }, "password": Object { "message": "One uppercase character", diff --git a/computed-types/src/computed-types.ts b/computed-types/src/computed-types.ts index 09949814..66427cd0 100644 --- a/computed-types/src/computed-types.ts +++ b/computed-types/src/computed-types.ts @@ -3,22 +3,14 @@ import { toNestError, validateFieldsNatively } from '@hookform/resolvers'; import type { ValidationError } from 'computed-types'; import type { Resolver } from './types'; -const parseErrorSchema = ( - computedTypesError: ValidationError, - parsedErrors: FieldErrors = {}, - path = '', -) => { +const parseErrorSchema = (computedTypesError: ValidationError) => { + const parsedErrors: FieldErrors = {}; return (computedTypesError.errors || []).reduce((acc, error) => { - const _currentPath = String(error.path[0]); - const _path = path ? `${path}.${_currentPath}` : _currentPath; - - acc[_path] = { + acc[error.path.join('.')] = { type: error.error.name, message: error.error.message, }; - parseErrorSchema(error.error, acc, _path); - return acc; }, parsedErrors); };