v1.0 with SW PWA enabled
This commit is contained in:
434
frontend/node_modules/zod/src/v3/tests/object.test.ts
generated
vendored
Normal file
434
frontend/node_modules/zod/src/v3/tests/object.test.ts
generated
vendored
Normal file
@ -0,0 +1,434 @@
|
||||
// @ts-ignore TS6133
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import * as z from "zod/v3";
|
||||
import { util } from "../helpers/util.js";
|
||||
|
||||
const Test = z.object({
|
||||
f1: z.number(),
|
||||
f2: z.string().optional(),
|
||||
f3: z.string().nullable(),
|
||||
f4: z.array(z.object({ t: z.union([z.string(), z.boolean()]) })),
|
||||
});
|
||||
|
||||
test("object type inference", () => {
|
||||
type TestType = {
|
||||
f1: number;
|
||||
f2?: string | undefined;
|
||||
f3: string | null;
|
||||
f4: { t: string | boolean }[];
|
||||
};
|
||||
|
||||
util.assertEqual<z.TypeOf<typeof Test>, TestType>(true);
|
||||
});
|
||||
|
||||
test("unknown throw", () => {
|
||||
const asdf: unknown = 35;
|
||||
expect(() => Test.parse(asdf)).toThrow();
|
||||
});
|
||||
|
||||
test("shape() should return schema of particular key", () => {
|
||||
const f1Schema = Test.shape.f1;
|
||||
const f2Schema = Test.shape.f2;
|
||||
const f3Schema = Test.shape.f3;
|
||||
const f4Schema = Test.shape.f4;
|
||||
|
||||
expect(f1Schema).toBeInstanceOf(z.ZodNumber);
|
||||
expect(f2Schema).toBeInstanceOf(z.ZodOptional);
|
||||
expect(f3Schema).toBeInstanceOf(z.ZodNullable);
|
||||
expect(f4Schema).toBeInstanceOf(z.ZodArray);
|
||||
});
|
||||
|
||||
test("correct parsing", () => {
|
||||
Test.parse({
|
||||
f1: 12,
|
||||
f2: "string",
|
||||
f3: "string",
|
||||
f4: [
|
||||
{
|
||||
t: "string",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Test.parse({
|
||||
f1: 12,
|
||||
f3: null,
|
||||
f4: [
|
||||
{
|
||||
t: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test("incorrect #1", () => {
|
||||
expect(() => Test.parse({} as any)).toThrow();
|
||||
});
|
||||
|
||||
test("nonstrict by default", () => {
|
||||
z.object({ points: z.number() }).parse({
|
||||
points: 2314,
|
||||
unknown: "asdf",
|
||||
});
|
||||
});
|
||||
|
||||
const data = {
|
||||
points: 2314,
|
||||
unknown: "asdf",
|
||||
};
|
||||
|
||||
test("strip by default", () => {
|
||||
const val = z.object({ points: z.number() }).parse(data);
|
||||
expect(val).toEqual({ points: 2314 });
|
||||
});
|
||||
|
||||
test("unknownkeys override", () => {
|
||||
const val = z.object({ points: z.number() }).strict().passthrough().strip().nonstrict().parse(data);
|
||||
|
||||
expect(val).toEqual(data);
|
||||
});
|
||||
|
||||
test("passthrough unknown", () => {
|
||||
const val = z.object({ points: z.number() }).passthrough().parse(data);
|
||||
|
||||
expect(val).toEqual(data);
|
||||
});
|
||||
|
||||
test("strip unknown", () => {
|
||||
const val = z.object({ points: z.number() }).strip().parse(data);
|
||||
|
||||
expect(val).toEqual({ points: 2314 });
|
||||
});
|
||||
|
||||
test("strict", () => {
|
||||
const val = z.object({ points: z.number() }).strict().safeParse(data);
|
||||
|
||||
expect(val.success).toEqual(false);
|
||||
});
|
||||
|
||||
test("catchall inference", () => {
|
||||
const o1 = z
|
||||
.object({
|
||||
first: z.string(),
|
||||
})
|
||||
.catchall(z.number());
|
||||
|
||||
const d1 = o1.parse({ first: "asdf", num: 1243 });
|
||||
util.assertEqual<number, (typeof d1)["asdf"]>(true);
|
||||
util.assertEqual<string, (typeof d1)["first"]>(true);
|
||||
});
|
||||
|
||||
test("catchall overrides strict", () => {
|
||||
const o1 = z.object({ first: z.string().optional() }).strict().catchall(z.number());
|
||||
|
||||
// should run fine
|
||||
// setting a catchall overrides the unknownKeys behavior
|
||||
o1.parse({
|
||||
asdf: 1234,
|
||||
});
|
||||
|
||||
// should only run catchall validation
|
||||
// against unknown keys
|
||||
o1.parse({
|
||||
first: "asdf",
|
||||
asdf: 1234,
|
||||
});
|
||||
});
|
||||
|
||||
test("catchall overrides strict", () => {
|
||||
const o1 = z
|
||||
.object({
|
||||
first: z.string(),
|
||||
})
|
||||
.strict()
|
||||
.catchall(z.number());
|
||||
|
||||
// should run fine
|
||||
// setting a catchall overrides the unknownKeys behavior
|
||||
o1.parse({
|
||||
first: "asdf",
|
||||
asdf: 1234,
|
||||
});
|
||||
});
|
||||
|
||||
test("test that optional keys are unset", async () => {
|
||||
const SNamedEntity = z.object({
|
||||
id: z.string(),
|
||||
set: z.string().optional(),
|
||||
unset: z.string().optional(),
|
||||
});
|
||||
const result = await SNamedEntity.parse({
|
||||
id: "asdf",
|
||||
set: undefined,
|
||||
});
|
||||
// eslint-disable-next-line ban/ban
|
||||
expect(Object.keys(result)).toEqual(["id", "set"]);
|
||||
});
|
||||
|
||||
test("test catchall parsing", async () => {
|
||||
const result = z.object({ name: z.string() }).catchall(z.number()).parse({ name: "Foo", validExtraKey: 61 });
|
||||
|
||||
expect(result).toEqual({ name: "Foo", validExtraKey: 61 });
|
||||
|
||||
const result2 = z
|
||||
.object({ name: z.string() })
|
||||
.catchall(z.number())
|
||||
.safeParse({ name: "Foo", validExtraKey: 61, invalid: "asdf" });
|
||||
|
||||
expect(result2.success).toEqual(false);
|
||||
});
|
||||
|
||||
test("test nonexistent keys", async () => {
|
||||
const Schema = z.union([z.object({ a: z.string() }), z.object({ b: z.number() })]);
|
||||
const obj = { a: "A" };
|
||||
const result = await Schema.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
test("test async union", async () => {
|
||||
const Schema2 = z.union([
|
||||
z.object({
|
||||
ty: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
ty: z.number(),
|
||||
}),
|
||||
]);
|
||||
|
||||
const obj = { ty: "A" };
|
||||
const result = await Schema2.spa(obj); // Works with 1.11.10, breaks with 2.0.0-beta.21
|
||||
expect(result.success).toEqual(true);
|
||||
});
|
||||
|
||||
test("test inferred merged type", async () => {
|
||||
const asdf = z.object({ a: z.string() }).merge(z.object({ a: z.number() }));
|
||||
type asdf = z.infer<typeof asdf>;
|
||||
util.assertEqual<asdf, { a: number }>(true);
|
||||
});
|
||||
|
||||
test("inferred merged object type with optional properties", async () => {
|
||||
const Merged = z
|
||||
.object({ a: z.string(), b: z.string().optional() })
|
||||
.merge(z.object({ a: z.string().optional(), b: z.string() }));
|
||||
type Merged = z.infer<typeof Merged>;
|
||||
util.assertEqual<Merged, { a?: string; b: string }>(true);
|
||||
// todo
|
||||
// util.assertEqual<Merged, { a?: string; b: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred unioned object type with optional properties", async () => {
|
||||
const Unioned = z.union([
|
||||
z.object({ a: z.string(), b: z.string().optional() }),
|
||||
z.object({ a: z.string().optional(), b: z.string() }),
|
||||
]);
|
||||
type Unioned = z.infer<typeof Unioned>;
|
||||
util.assertEqual<Unioned, { a: string; b?: string } | { a?: string; b: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred enum type", async () => {
|
||||
const Enum = z.object({ a: z.string(), b: z.string().optional() }).keyof();
|
||||
|
||||
expect(Enum.Values).toEqual({
|
||||
a: "a",
|
||||
b: "b",
|
||||
});
|
||||
expect(Enum.enum).toEqual({
|
||||
a: "a",
|
||||
b: "b",
|
||||
});
|
||||
expect(Enum._def.values).toEqual(["a", "b"]);
|
||||
type Enum = z.infer<typeof Enum>;
|
||||
util.assertEqual<Enum, "a" | "b">(true);
|
||||
});
|
||||
|
||||
test("inferred partial object type with optional properties", async () => {
|
||||
const Partial = z.object({ a: z.string(), b: z.string().optional() }).partial();
|
||||
type Partial = z.infer<typeof Partial>;
|
||||
util.assertEqual<Partial, { a?: string; b?: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred picked object type with optional properties", async () => {
|
||||
const Picked = z.object({ a: z.string(), b: z.string().optional() }).pick({ b: true });
|
||||
type Picked = z.infer<typeof Picked>;
|
||||
util.assertEqual<Picked, { b?: string }>(true);
|
||||
});
|
||||
|
||||
test("inferred type for unknown/any keys", () => {
|
||||
const myType = z.object({
|
||||
anyOptional: z.any().optional(),
|
||||
anyRequired: z.any(),
|
||||
unknownOptional: z.unknown().optional(),
|
||||
unknownRequired: z.unknown(),
|
||||
});
|
||||
type myType = z.infer<typeof myType>;
|
||||
util.assertEqual<
|
||||
myType,
|
||||
{
|
||||
anyOptional?: any;
|
||||
anyRequired?: any;
|
||||
unknownOptional?: unknown;
|
||||
unknownRequired?: unknown;
|
||||
}
|
||||
>(true);
|
||||
});
|
||||
|
||||
test("setKey", () => {
|
||||
const base = z.object({ name: z.string() });
|
||||
const withNewKey = base.setKey("age", z.number());
|
||||
|
||||
type withNewKey = z.infer<typeof withNewKey>;
|
||||
util.assertEqual<withNewKey, { name: string; age: number }>(true);
|
||||
withNewKey.parse({ name: "asdf", age: 1234 });
|
||||
});
|
||||
|
||||
test("strictcreate", async () => {
|
||||
const strictObj = z.strictObject({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const syncResult = strictObj.safeParse({ name: "asdf", unexpected: 13 });
|
||||
expect(syncResult.success).toEqual(false);
|
||||
|
||||
const asyncResult = await strictObj.spa({ name: "asdf", unexpected: 13 });
|
||||
expect(asyncResult.success).toEqual(false);
|
||||
});
|
||||
|
||||
test("object with refine", async () => {
|
||||
const schema = z
|
||||
.object({
|
||||
a: z.string().default("foo"),
|
||||
b: z.number(),
|
||||
})
|
||||
.refine(() => true);
|
||||
expect(schema.parse({ b: 5 })).toEqual({ b: 5, a: "foo" });
|
||||
const result = await schema.parseAsync({ b: 5 });
|
||||
expect(result).toEqual({ b: 5, a: "foo" });
|
||||
});
|
||||
|
||||
test("intersection of object with date", async () => {
|
||||
const schema = z.object({
|
||||
a: z.date(),
|
||||
});
|
||||
expect(schema.and(schema).parse({ a: new Date(1637353595983) })).toEqual({
|
||||
a: new Date(1637353595983),
|
||||
});
|
||||
const result = await schema.parseAsync({ a: new Date(1637353595983) });
|
||||
expect(result).toEqual({ a: new Date(1637353595983) });
|
||||
});
|
||||
|
||||
test("intersection of object with refine with date", async () => {
|
||||
const schema = z
|
||||
.object({
|
||||
a: z.date(),
|
||||
})
|
||||
.refine(() => true);
|
||||
expect(schema.and(schema).parse({ a: new Date(1637353595983) })).toEqual({
|
||||
a: new Date(1637353595983),
|
||||
});
|
||||
const result = await schema.parseAsync({ a: new Date(1637353595983) });
|
||||
expect(result).toEqual({ a: new Date(1637353595983) });
|
||||
});
|
||||
|
||||
test("constructor key", () => {
|
||||
const person = z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
expect(() =>
|
||||
person.parse({
|
||||
name: "bob dylan",
|
||||
constructor: 61,
|
||||
})
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
test("constructor key", () => {
|
||||
const Example = z.object({
|
||||
prop: z.string(),
|
||||
opt: z.number().optional(),
|
||||
arr: z.string().array(),
|
||||
});
|
||||
|
||||
type Example = z.infer<typeof Example>;
|
||||
util.assertEqual<keyof Example, "prop" | "opt" | "arr">(true);
|
||||
});
|
||||
|
||||
test("unknownkeys merging", () => {
|
||||
// This one is "strict"
|
||||
const schemaA = z
|
||||
.object({
|
||||
a: z.string(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
// This one is "strip"
|
||||
const schemaB = z
|
||||
.object({
|
||||
b: z.string(),
|
||||
})
|
||||
.catchall(z.string());
|
||||
|
||||
const mergedSchema = schemaA.merge(schemaB);
|
||||
type mergedSchema = typeof mergedSchema;
|
||||
util.assertEqual<mergedSchema["_def"]["unknownKeys"], "strip">(true);
|
||||
expect(mergedSchema._def.unknownKeys).toEqual("strip");
|
||||
|
||||
util.assertEqual<mergedSchema["_def"]["catchall"], z.ZodString>(true);
|
||||
expect(mergedSchema._def.catchall instanceof z.ZodString).toEqual(true);
|
||||
});
|
||||
|
||||
const personToExtend = z.object({
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
});
|
||||
|
||||
test("extend() should return schema with new key", () => {
|
||||
const PersonWithNickname = personToExtend.extend({ nickName: z.string() });
|
||||
type PersonWithNickname = z.infer<typeof PersonWithNickname>;
|
||||
|
||||
const expected = { firstName: "f", nickName: "n", lastName: "l" };
|
||||
const actual = PersonWithNickname.parse(expected);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
util.assertEqual<keyof PersonWithNickname, "firstName" | "lastName" | "nickName">(true);
|
||||
util.assertEqual<PersonWithNickname, { firstName: string; lastName: string; nickName: string }>(true);
|
||||
});
|
||||
|
||||
test("extend() should have power to override existing key", () => {
|
||||
const PersonWithNumberAsLastName = personToExtend.extend({
|
||||
lastName: z.number(),
|
||||
});
|
||||
type PersonWithNumberAsLastName = z.infer<typeof PersonWithNumberAsLastName>;
|
||||
|
||||
const expected = { firstName: "f", lastName: 42 };
|
||||
const actual = PersonWithNumberAsLastName.parse(expected);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
util.assertEqual<PersonWithNumberAsLastName, { firstName: string; lastName: number }>(true);
|
||||
});
|
||||
|
||||
test("passthrough index signature", () => {
|
||||
const a = z.object({ a: z.string() });
|
||||
type a = z.infer<typeof a>;
|
||||
util.assertEqual<{ a: string }, a>(true);
|
||||
const b = a.passthrough();
|
||||
type b = z.infer<typeof b>;
|
||||
util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true);
|
||||
});
|
||||
|
||||
test("xor", () => {
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
type XOR<T, U> = T extends object ? (U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : U) : T;
|
||||
|
||||
type A = { name: string; a: number };
|
||||
type B = { name: string; b: number };
|
||||
type C = XOR<A, B>;
|
||||
type Outer = { data: C };
|
||||
|
||||
const _Outer: z.ZodType<Outer> = z.object({
|
||||
data: z.union([z.object({ name: z.string(), a: z.number() }), z.object({ name: z.string(), b: z.number() })]),
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user