187 lines
4.4 KiB
TypeScript
187 lines
4.4 KiB
TypeScript
// @ts-ignore TS6133
|
|
import { expect, test } from "vitest";
|
|
|
|
import * as z from "zod/v3";
|
|
import { util } from "../helpers/util.js";
|
|
|
|
test("preprocess", () => {
|
|
const schema = z.preprocess((data) => [data], z.string().array());
|
|
|
|
const value = schema.parse("asdf");
|
|
expect(value).toEqual(["asdf"]);
|
|
util.assertEqual<(typeof schema)["_input"], unknown>(true);
|
|
});
|
|
|
|
test("async preprocess", async () => {
|
|
const schema = z.preprocess(async (data) => [data], z.string().array());
|
|
|
|
const value = await schema.parseAsync("asdf");
|
|
expect(value).toEqual(["asdf"]);
|
|
});
|
|
|
|
test("preprocess ctx.addIssue with parse", () => {
|
|
expect(() => {
|
|
z.preprocess((data, ctx) => {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: `${data} is not one of our allowed strings`,
|
|
});
|
|
return data;
|
|
}, z.string()).parse("asdf");
|
|
}).toThrow(
|
|
JSON.stringify(
|
|
[
|
|
{
|
|
code: "custom",
|
|
message: "asdf is not one of our allowed strings",
|
|
path: [],
|
|
},
|
|
],
|
|
null,
|
|
2
|
|
)
|
|
);
|
|
});
|
|
|
|
test("preprocess ctx.addIssue non-fatal by default", () => {
|
|
try {
|
|
z.preprocess((data, ctx) => {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: `custom error`,
|
|
});
|
|
return data;
|
|
}, z.string()).parse(1234);
|
|
} catch (err) {
|
|
z.ZodError.assert(err);
|
|
expect(err.issues.length).toEqual(2);
|
|
}
|
|
});
|
|
|
|
test("preprocess ctx.addIssue fatal true", () => {
|
|
try {
|
|
z.preprocess((data, ctx) => {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: `custom error`,
|
|
fatal: true,
|
|
});
|
|
return data;
|
|
}, z.string()).parse(1234);
|
|
} catch (err) {
|
|
z.ZodError.assert(err);
|
|
expect(err.issues.length).toEqual(1);
|
|
}
|
|
});
|
|
|
|
test("async preprocess ctx.addIssue with parse", async () => {
|
|
const schema = z.preprocess(async (data, ctx) => {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: `custom error`,
|
|
});
|
|
return data;
|
|
}, z.string());
|
|
|
|
expect(await schema.safeParseAsync("asdf")).toMatchInlineSnapshot(`
|
|
{
|
|
"error": [ZodError: [
|
|
{
|
|
"code": "custom",
|
|
"message": "custom error",
|
|
"path": []
|
|
}
|
|
]],
|
|
"success": false,
|
|
}
|
|
`);
|
|
});
|
|
|
|
test("preprocess ctx.addIssue with parseAsync", async () => {
|
|
const result = await z
|
|
.preprocess(async (data, ctx) => {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: `${data} is not one of our allowed strings`,
|
|
});
|
|
return data;
|
|
}, z.string())
|
|
.safeParseAsync("asdf");
|
|
|
|
expect(JSON.parse(JSON.stringify(result))).toEqual({
|
|
success: false,
|
|
error: {
|
|
issues: [
|
|
{
|
|
code: "custom",
|
|
message: "asdf is not one of our allowed strings",
|
|
path: [],
|
|
},
|
|
],
|
|
name: "ZodError",
|
|
},
|
|
});
|
|
});
|
|
|
|
test("z.NEVER in preprocess", () => {
|
|
const foo = z.preprocess((val, ctx) => {
|
|
if (!val) {
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "bad" });
|
|
return z.NEVER;
|
|
}
|
|
return val;
|
|
}, z.number());
|
|
|
|
type foo = z.infer<typeof foo>;
|
|
util.assertEqual<foo, number>(true);
|
|
const arg = foo.safeParse(undefined);
|
|
expect(arg.error!.issues).toHaveLength(2);
|
|
expect(arg.error!.issues[0].message).toEqual("bad");
|
|
});
|
|
test("preprocess as the second property of object", () => {
|
|
const schema = z.object({
|
|
nonEmptyStr: z.string().min(1),
|
|
positiveNum: z.preprocess((v) => Number(v), z.number().positive()),
|
|
});
|
|
const result = schema.safeParse({
|
|
nonEmptyStr: "",
|
|
positiveNum: "",
|
|
});
|
|
expect(result.success).toEqual(false);
|
|
if (!result.success) {
|
|
expect(result.error.issues.length).toEqual(2);
|
|
expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.too_small);
|
|
expect(result.error.issues[1].code).toEqual(z.ZodIssueCode.too_small);
|
|
}
|
|
});
|
|
|
|
test("preprocess validates with sibling errors", () => {
|
|
expect(() => {
|
|
z.object({
|
|
// Must be first
|
|
missing: z.string().refine(() => false),
|
|
preprocess: z.preprocess((data: any) => data?.trim(), z.string().regex(/ asdf/)),
|
|
}).parse({ preprocess: " asdf" });
|
|
}).toThrow(
|
|
JSON.stringify(
|
|
[
|
|
{
|
|
code: "invalid_type",
|
|
expected: "string",
|
|
received: "undefined",
|
|
path: ["missing"],
|
|
message: "Required",
|
|
},
|
|
{
|
|
validation: "regex",
|
|
code: "invalid_string",
|
|
message: "Invalid",
|
|
path: ["preprocess"],
|
|
},
|
|
],
|
|
null,
|
|
2
|
|
)
|
|
);
|
|
});
|