Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Cbridger-mywellabee opened this issue Jun 24, 2024 · 3 comments

Comments

@Cbridger-mywellabee
Copy link

Cbridger-mywellabee commented Jun 24, 2024

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: '[email protected]' },
    });
    
 console.log(JSON.stringify(errors, null, 2));

it outputs:

 LOG  s [email protected] [email protected]
 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",

@marquesgabriel
Copy link

Hello @Cbridger-mywellabee, did you manage to resolve the issue you faced? My team and I are facing the same issue here and we could not find a solution yet.

@Cbridger-mywellabee
Copy link
Author

Cbridger-mywellabee commented Sep 24, 2024

Yeah, ended up adding a trigger to the onChangeText callback:

    const {
        control,
        trigger,
        ...
    } = useForm({
    
    ...

 <Controller
    control={control}
    name="newPassword"
    render={({
        field: { onChange, value, ref },
    }) => (
            <TextInput
                ref={ref}
                value={value}
                onChangeText={(text: string) => {
                    onChange(text);
                    trigger('newPasswordConfirmation');
                    trigger('currentPassword');
                }}

@marquesgabriel

@marquesgabriel
Copy link

Thanks @Cbridger-mywellabee . I thought about this last night, but doing this honestly feels like a workaround, but it is the only resolution while working with reack-hook-form as they validate one field at a time.

Thanks for sharing and have a great week!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants