Skip to content

Commit

Permalink
feat(validationSchema): support yup transforms in validate & submit (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
quantizor committed May 27, 2023
1 parent abbec18 commit 2f53b70
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/fluffy-rivers-rest.md
@@ -0,0 +1,5 @@
---
'formik': minor
---

Add support for Yup ["transforms"](https://github.com/jquense/yup#parsing-transforms).
21 changes: 16 additions & 5 deletions packages/formik/src/Formik.tsx
Expand Up @@ -218,10 +218,7 @@ export function useFormik<Values extends FormikValues = FormikValues>({
*/
const runValidationSchema = React.useCallback(
(values: Values, field?: string): Promise<FormikErrors<Values>> => {
const validationSchema = props.validationSchema;
const schema = isFunction(validationSchema)
? validationSchema(field)
: validationSchema;
const schema = getValidationSchema(props.validationSchema);
const promise =
field && schema.validateAt
? schema.validateAt(field, values)
Expand Down Expand Up @@ -845,7 +842,11 @@ export function useFormik<Values extends FormikValues = FormikValues>({
};

const executeSubmit = useEventCallback(() => {
return onSubmit(state.values, imperativeMethods);
const schema = getValidationSchema(props.validationSchema);
const actualizedValues =
schema && schema.cast ? schema.cast(state.values) : state.values;

return onSubmit(actualizedValues, imperativeMethods);
});

const handleReset = useEventCallback(e => {
Expand Down Expand Up @@ -1023,6 +1024,16 @@ export function Formik<
);
}

function getValidationSchema<Values extends FormikValues = FormikValues>(
validationSchema?: FormikConfig<Values>['validationSchema']
) {
if (!validationSchema) {
return;
}

return isFunction(validationSchema) ? validationSchema() : validationSchema;
}

function warnAboutMissingIdentifier({
htmlContent,
documentationAnchorLink,
Expand Down
68 changes: 66 additions & 2 deletions packages/formik/test/Formik.test.tsx
Expand Up @@ -1435,8 +1435,8 @@ describe('<Formik>', () => {
await act(async () => {
try {
await getProps().validateForm();
} catch ({ message }) {
caughtError = message;
} catch (err) {
caughtError = (err as Yup.ValidationError).message;
}
});

Expand All @@ -1450,4 +1450,68 @@ describe('<Formik>', () => {

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

it('transforms in yup schema are applied on validation', async () => {
const validationSchema = Yup.object({
users: Yup.array().of(
Yup.object({
firstName: Yup.string()
.transform(currentValue =>
currentValue.split('').reverse().join('')
)
// @ts-expect-error incorrect typing for second arg
.oneOf(['foo'], x => x.value),
})
),
});

const { getProps } = renderFormik({
initialValues: { users: [{ firstName: 'foo' }] },
validationSchema,
});

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

expect(getProps().errors).toEqual({
users: [
{
// the transform reverses "foo" to "oof", which then fails the `oneOf` assertion
firstName: 'oof',
},
],
});
});
});

it('transforms in yup schema are applied on submit', async () => {
const validationSchema = Yup.object({
users: Yup.array().of(
Yup.object({
firstName: Yup.string().transform(currentValue =>
currentValue.split('').reverse().join('')
),
})
),
});

const spy = jest.fn();

const { getProps } = renderFormik({
initialValues: { users: [{ firstName: 'foo' }] },
onSubmit: spy,
validationSchema,
});

await act(async () => {
await getProps().submitForm();

expect(spy).toHaveBeenCalledWith(
{
users: [{ firstName: 'oof' }],
},
expect.anything()
);
});
});
});
9 changes: 6 additions & 3 deletions packages/formik/test/withFormik.test.tsx
Expand Up @@ -134,15 +134,18 @@ describe('withFormik()', () => {
});

it('calls validationSchema', async () => {
const validate = jest.fn(() => Promise.resolve());
const validationSchema = Yup.object();

jest.spyOn(validationSchema, 'validate');

const { getProps } = renderWithFormik({
validationSchema: { validate },
validationSchema,
});

act(() => {
getProps().submitForm();
});
await waitFor(() => expect(validate).toHaveBeenCalled());
await waitFor(() => expect(validationSchema.validate).toHaveBeenCalled());
});

it('calls validationSchema function with props', async () => {
Expand Down

1 comment on commit 2f53b70

@vercel
Copy link

@vercel vercel bot commented on 2f53b70 May 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

formik-docs – ./website

formik-docs-jared.vercel.app
formik-docs.vercel.app
formik-docs-git-master-jared.vercel.app
formik.org
www.formik.org

Please sign in to comment.