jquense / yup

Dead simple Object schema validation
MIT License
22.72k stars 925 forks source link

`when` and `test` stopped working together #2205

Open Sinled opened 4 months ago

Sinled commented 4 months ago

Describe the bug After migrating to yup v1.4 when and test stopped working together, worked fine in 0.32.11.

To Reproduce

Codesanbox removed ability to run tests, https://codesandbox.io/docs/learn/sandboxes/faq#where-can-i-find-the-tests-tab, so I am not sure where to add runnable test

But here simplified code and test example that worked in previous versions of yup:

Code here ```ts import { object, mixed, string } from 'yup'; import { it, expect } from 'vitest'; const schema = object().shape({ value: mixed() .label('Value') .required() .when('$model.isStringValueType', { is: true, then: () => string().required(), }) .test('is-unique-value', 'Value should be unique', function (newValue) { if (!newValue) { return true; } const values = this.parent.siblingValues.filter(({ otherValue }: { otherValue: string | number }) => { return otherValue === newValue; }); return values.length === 1; }), }); it('should be invalid if "when" is not entered', async () => { await expect( schema.isValid( { siblingValues: [{ otherValue: 'foo' }, { otherValue: 'foo' }], value: 'foo', }, { context: { model: { isStringValueType: false } } }, ), ).resolves.toBe(false); }); it('should be invalid if not a string', async () => { await expect( schema.isValid( { siblingValues: [{ otherValue: 'foo' }], value: 1, }, { context: { model: { isStringValueType: true } } }, ), ).resolves.toBe(false); }); it('should be invalid if "when" is entered and has similar siblings', async () => { await expect( schema.isValid( { siblingValues: [{ otherValue: 'foo' }, { otherValue: 'foo' }], value: 'foo', }, { context: { model: { isStringValueType: true } } }, ), ).resolves.toBe(false); }); ```

At the moment, 2nd and 3rd test fails.

Expected behavior tests should pass, both .when and .test branches should be checked

Platform (please complete the following information):

Additional context This is recreation of https://github.com/jquense/yup/issues/2179

jquense commented 4 months ago

This is happening because your when is discarding the current schema and returning a fresh one without your custom test:

.when('$model.isStringValueType', {
    is: true,
-    then: () => string().required(),
+    then: schema => schema.required(),
})
Sinled commented 4 months ago

@jquense thanks for reply, but what should I do if I need to return different schemas? e.g. string or number depending on condition?

It worked fine before, it is not very clear what to do now.

jquense commented 4 months ago

Switching types isn't really supported, it didn't work fine before, it was very inconsistent and often produced broken schema which is why it was removed. You are welcome to return a brand new schema still, but it won't be automatically concated with the old one. You can approximate the old behavior by doing the concat yourself, schema=> schema.concat(string().whatever())