react-hook-form / resolvers

📋 Validation resolvers: Yup, Zod, Superstruct, Joi, Vest, Class Validator, io-ts, Nope, computed-types, typanion, Ajv, TypeBox, ArkType, Valibot, effect-ts and VineJS
https://react-hook-form.com/
MIT License
1.67k stars 151 forks source link

Yup validation with when clauses not correctly surfaced to errors object #694

Open Cbridger-mywellabee opened 3 weeks ago

Cbridger-mywellabee commented 3 weeks ago

Describe the bug I have this react native code:

const passwordValidation = (schema) =>
    schema
        .min(10, 'Password must be at least 10 characters')
        .matches(
            /(?=.*[A-Z])/,
            'Password must have at least one uppercase letter',
        )
        .matches(
            /(?=.*[a-z])/,
            'Password must have at least one lowercase letter',
        )
        .matches(/(?=.*[0-9])/, 'Password must have at least one number')
        .matches(
            /(?=.*[!@#$%^&*])/,
            'Password must have at least one special character',
        );

const schema = yup.object({
    firstName: yup.string().required('First name is required'),
    lastName: yup.string().required('Last name is required'),
    email: yup.string().email('Invalid email').required(),
    currentPassword: yup
        .string()
        .when(['newPassword', 'email', '$originalEmail'], {
            is: (newPassword, email, originalEmail) => {
                console.log(newPassword, email, originalEmail);
                return !!newPassword || email !== originalEmail;
            },
            then: (schema) => {
                console.log('running then');
                return schema.required('Current password is required');
            },
            otherwise: (schema) => {
                console.log('running otherwise: ');
                return schema.notRequired();
            },
        }),
    newPassword: passwordValidation(yup.string().notRequired()),
    newPasswordCopy: yup.string().when('newPassword', {
        is: (newPassword) => !!newPassword,
        then: (schema) =>
            schema
                .required('New password confirmation is required')
                .oneOf([yup.ref('newPassword')], 'Passwords must match'),
        otherwise: (schema) => schema.notRequired(),
    }),
});

...

    const {
        control,
        handleSubmit,
        formState: { errors },
    } = useForm({
        mode: 'all',
        criteriaMode: 'all',
        reValidateMode: 'onChange',
        resolver: async (data, context, options) => {
            var resolverResults = await yupResolver(schema)(
                data,
                context,
                options,
            );
            console.log('validation result', resolverResults);

            return resolverResults;
        },
        defaultValues: {
            firstName: auth.user.name,
            lastName: auth.user.lastname,
            email: auth.user.email,
            newPassword: null,
            currentPassword: null,
            newPasswordCopy: null,
        },
        context: { originalEmail: 'test@gmail.com' },
    });

 console.log(JSON.stringify(errors, null, 2));

it outputs:

 LOG  s Charles.bridger+test5@mywellabee.com test@gmail.com
 LOG  running then
 LOG  validation result {"errors": {"currentPassword": {"message": "Current password is required", "ref": "currentPassword", "type": "required", "types": [Object]}, "newPassword": {"message": "Password must be at least 10 characters", "ref": "newPassword", "type": "min", "types": [Object]}, "newPasswordCopy": {"message": "New password confirmation is required", "ref": "newPasswordCopy", "type": "nullable", "types": [Object]}}, "values": {}}
 LOG  {
  "newPassword": {
    "message": "Password must be at least 10 characters",
    "type": "min",
    "types": {
      "min": "Password must be at least 10 characters",
      "matches": [
        "Password must have at least one uppercase letter",
        "Password must have at least one number",
        "Password must have at least one special character"
      ]
    },
    "ref": "newPassword"
  }
}

image

Expected behavior The Errors object should contain errors for currentPassword and newPasswordCopy

Snack reproducing error https://snack.expo.dev/@cdbridger-mywellabee/yupresolvererror

Versions: "expo": "~51.0.12", "react": "18.2.0", "react-hook-form": "^7.52.0", "react-native": "0.74.2", "yup": "^1.4.0" "@hookform/resolvers": "^3.6.0",