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

Feature: Pass Yup context to validationSchema using new prop validationSchemaContext in <Formik> #3852

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/api/formik.md
Expand Up @@ -458,3 +458,7 @@ and/or `initialValues` change.
[A Yup schema](https://github.com/jquense/yup) or a function that returns a Yup
schema. This is used for validation. Errors are mapped by key to the inner
component's `errors`. Its keys should match those of `values`.

### `validationSchemaContext?: object`

A [context object](https://github.com/jquense/yup#schemavalidatevalue-any-options-object-promiseinfertypeschema-validationerror) that is passed to the [Yup schema](https://github.com/jquense/yup) provided via the [validationSchema prop](#validationschema-schema----schema).
6 changes: 4 additions & 2 deletions packages/formik/src/Formik.tsx
Expand Up @@ -235,8 +235,10 @@ export function useFormik<Values extends FormikValues = FormikValues>({
: validationSchema;
const promise =
field && schema.validateAt
? schema.validateAt(field, values)
: validateYupSchema(values, schema);
? schema.validateAt(field, values, {
context: props.validationSchemaContext
})
: validateYupSchema(values, schema, false, props.validationSchemaContext);
return new Promise((resolve, reject) => {
promise.then(
() => {
Expand Down
6 changes: 6 additions & 0 deletions packages/formik/src/types.tsx
Expand Up @@ -223,6 +223,12 @@ export interface FormikConfig<Values> extends FormikSharedConfig {
values: Values,
formikHelpers: FormikHelpers<Values>
) => void | Promise<any>;

/**
* A context object to be passed to the Yup schema's `validate` method.
*/
validationSchemaContext?: any;

/**
* A Yup Schema or a function that returns a Yup schema
*/
Expand Down
24 changes: 24 additions & 0 deletions packages/formik/test/Formik.test.tsx
Expand Up @@ -1454,4 +1454,28 @@ describe('<Formik>', () => {

expect(innerRef.current).toEqual(getProps());
});

it('should pass context to validationSchema', async () => {
const validationSchema = Yup.object().shape({
usernameOrEmail: Yup.string().when(
'$validateAsEmail',
(validateAsEmail, schema) =>
validateAsEmail ? schema.email('Invalid email') : schema
),
});

const { getProps } = renderFormik({
initialValues: { usernameOrEmail: 'john' },
validationSchema,
validationSchemaContext: { validateAsEmail: true },
});

await act(async () => {
await getProps().validateForm();
});

expect(getProps().errors).toEqual({
usernameOrEmail: 'Invalid email',
});
});
});
18 changes: 18 additions & 0 deletions packages/formik/test/yupHelpers.test.ts
Expand Up @@ -22,6 +22,12 @@ const deepNestedSchema = Yup.object({
}),
});

const whenContextSchema = Yup.object().shape({
name: Yup.string().when('$isNameRequired', (isNameRequired, schema) => {
return isNameRequired ? schema.required('name is required') : schema;
}),
});

describe('Yup helpers', () => {
describe('yupToFormErrors()', () => {
it('should transform Yup ValidationErrors into an object', async () => {
Expand Down Expand Up @@ -109,5 +115,17 @@ describe('Yup helpers', () => {
]);
}
});

it('should provide context values as context to when method', async () => {
try {
await validateYupSchema({ name: '' }, whenContextSchema, false, {
isNameRequired: true,
});
} catch (e) {
const err = e as Yup.ValidationError;
expect(err.name).toEqual('ValidationError');
expect(err.errors).toEqual(['name is required']);
}
});
});
});