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):
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:
required to caution against schema types with non-falsey defaults by default - I think that's only object(), right?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
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
requiredas one of their first validations - it's such a fundamental test. Thatrequireddoesn'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:requiredto caution against schema types with non-falsey defaults by default - I think that's onlyobject(), right?required()on Object that rejects empty objects (similar to howstring().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