Yup: Nested object(): validation ignores required()

Created on 27 Oct 2019  路  4Comments  路  Source: jquense/yup

Describe the bug
when an ObjectSchema's field is itself an ObjectSchema, invoking .required() on it has no effect

To Reproduce

  it('enforces required object fields', () => {
    const schema = object({
      a: object({
        b: mixed()
      }).required(),
    })

   // this works as expected
    expect(schema.isValidSync({a: {b: 'foo'}})).toBe(true)
    expect(schema.isValidSync({a: {b: undefined}})).toBe(true)
    expect(schema.isValidSync({a: {}})).toBe(true)
    expect(schema.isValidSync({a: null})).toBe(false)

    // but this doesn't!
    expect(schema.isValidSync({a: undefined})).toBe(false) // fails
    expect(schema.isValidSync({})).toBe(false) // fails
  })

Expected behavior
The object should be considered invalid if field a is undefined or not set.

Platform (please complete the following information):

  • Browser: any (tested in node)
  • Version 0.27.0
invalid

Most helpful comment

Hi @jquense, I appreciate that this is behaving as intended and not a bug in the technical sense, and thinking through it again I appreciate that object schemas behave exactly the same when nested as fields vs when used directly, so that's all consistent and good.

New users like me are likely to use required as one of their first validations - it's such a fundamental test. That required doesn't do anything by itself for certain schema types really threw me! So while it may not be a bug I feel there is a user need for clarification. I want to suggest two options:

  1. Modify the documentation for required to caution against schema types with non-falsey defaults by default - I think that's only object(), right?
  2. Provide an override of required() on Object that rejects empty objects (similar to how string().required() is an override that rejects empty strings)

I prefer option (2) from a usability point of view, personally, but would appreciate some thoughts. I'm happy to submit a PR if we can agree on the right approach

All 4 comments

Until a fix is published, adding .default({}) to your required object and .default(undefined) for your notRequired ones should resolve issues with nested required and notRequired tests.

Thanks @andristrieb, this approach is a good workaround!

For the intended behaviour, however, I need to set .default(undefined) for my _required_ objects, otherwise {a: undefined} casts to {a: {}} which passes the required check.

Object's come with a default value automatically. When a field value is undefined it uses the default. If you don't want a nested object to be filled in automatically, when it's undefined, then set the nested object to .nullable().default(null)

Hi @jquense, I appreciate that this is behaving as intended and not a bug in the technical sense, and thinking through it again I appreciate that object schemas behave exactly the same when nested as fields vs when used directly, so that's all consistent and good.

New users like me are likely to use required as one of their first validations - it's such a fundamental test. That required doesn't do anything by itself for certain schema types really threw me! So while it may not be a bug I feel there is a user need for clarification. I want to suggest two options:

  1. Modify the documentation for required to caution against schema types with non-falsey defaults by default - I think that's only object(), right?
  2. Provide an override of required() on Object that rejects empty objects (similar to how string().required() is an override that rejects empty strings)

I prefer option (2) from a usability point of view, personally, but would appreciate some thoughts. I'm happy to submit a PR if we can agree on the right approach

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juni0r picture juni0r  路  3Comments

ScreamZ picture ScreamZ  路  4Comments

haddyo picture haddyo  路  3Comments

RobBednark picture RobBednark  路  3Comments

aprat84 picture aprat84  路  4Comments