Last active
February 10, 2025 16:53
-
-
Save jakobvase/825d5c5ae012de77194485ed1301d72b to your computer and use it in GitHub Desktop.
yup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { object, string } from 'yup'; | |
describe('yup', () => { | |
/** | |
* I've had some trouble getting yup to work as I want, and I think it's unintuitive. | |
* But I have to use it, so I'm writing down these tests so I can actually see what does what. | |
* | |
* A few key gotchas: | |
* * The default value of an object is `{}`, so `object({a: string()})` will allow `undefined`. | |
* The way to get around this is to add `default(undefined).required()` to all objects. | |
* * With `strict(true)`, all transforms are off the table. Can't transform anything. | |
* * With `strict(false)`, everything is coerced, so `string()` will allow `123`. | |
* * Allowing undefined is the default. So `string()` will allow `undefined`. | |
* * Yup will coerce strings and numbers to null, so `object(...).nullable()` will accept `"abc"` unless | |
* you add `strict`, but then of course all transforms are off the table. | |
*/ | |
it("transforms this empty string to undefined if it's undefined", () => { | |
const schema = string().transform(s => (s == null || s === '' ? undefined : s)); | |
// .optional(); // allowing undefined is the default | |
expect(schema.validateSync('')).toBeUndefined(); | |
expect(schema.validateSync(null)).toBeUndefined(); | |
expect(schema.validateSync(undefined)).toBeUndefined(); | |
expect(schema.validateSync('abc')).toBe('abc'); | |
}); | |
const schema = object({ | |
a: string() | |
.transform(s => (s == null || s === '' ? undefined : s)) // transform empty string and null to undefined | |
// .optional() // allows undefined, not null. Also is the default. | |
// .required() // disallows undefined | |
.min(1), // disallows empty strings. Doesn't matter in the `strict(false)` case, but when `strict(true)`, we | |
// suddenly allow empty strings because the transform is just skipped. | |
}) | |
// .strict(true) // disables transforms so we throw on unknown values, but also disables transforms inside the object | |
.noUnknown(true) // will remove any unknown values. If `strict(true)`, can't remove them, so throws instead | |
.default(undefined) // the default default for object is {} | |
.required(); // and after we've defaulted to undefined, we can now fail if it's not there | |
it("transforms this empty string in an object to undefined if it's undefined", () => { | |
expect(schema.validateSync({})).toEqual({}); | |
expect(schema.validateSync({ a: undefined })).toEqual({ a: undefined }); | |
expect(schema.validateSync({ a: null })).toEqual({ a: undefined }); | |
expect(schema.validateSync({ a: '' })).toEqual({ a: undefined }); | |
expect(schema.validateSync({ a: 'abc' })).toEqual({ a: 'abc' }); | |
expect(schema.validateSync({ a: 123 })).toEqual({ a: '123' }); // Not intuitive. | |
expect(schema.validateSync({ b: 'abc' })).toEqual({}); // Weird. | |
}); | |
it("doesn't validate all these weird cases", () => { | |
expect(() => schema.validateSync(undefined)).toThrow(); | |
expect(() => schema.validateSync(null)).toThrow(); | |
// expect(() => schema.validateSync({ a: 123 })).toThrow(); // requires strict(true) | |
// expect(() => schema.validateSync({ b: "" })).toThrow(); // requires strict(true) | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment