Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
4.6 KiB
Text
163 lines
4.6 KiB
Text
import { expect, expectTypeOf, test } from "vitest";
|
|
import * as z from "zod/v4";
|
|
|
|
test("successful validation", () => {
|
|
const testTuple = z.tuple([z.string(), z.number()]);
|
|
expectTypeOf<typeof testTuple._output>().toEqualTypeOf<[string, number]>();
|
|
|
|
const val = testTuple.parse(["asdf", 1234]);
|
|
expect(val).toEqual(val);
|
|
|
|
const r1 = testTuple.safeParse(["asdf", "asdf"]);
|
|
expect(r1.success).toEqual(false);
|
|
expect(r1.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"expected": "number",
|
|
"code": "invalid_type",
|
|
"path": [
|
|
1
|
|
],
|
|
"message": "Invalid input: expected number, received string"
|
|
}
|
|
]]
|
|
`);
|
|
|
|
const r2 = testTuple.safeParse(["asdf", 1234, true]);
|
|
expect(r2.success).toEqual(false);
|
|
expect(r2.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"origin": "array",
|
|
"code": "too_big",
|
|
"maximum": 2,
|
|
"path": [],
|
|
"message": "Too big: expected array to have <2 items"
|
|
}
|
|
]]
|
|
`);
|
|
|
|
const r3 = testTuple.safeParse({});
|
|
expect(r3.success).toEqual(false);
|
|
expect(r3.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"expected": "tuple",
|
|
"code": "invalid_type",
|
|
"path": [],
|
|
"message": "Invalid input: expected tuple, received object"
|
|
}
|
|
]]
|
|
`);
|
|
});
|
|
|
|
test("async validation", async () => {
|
|
const testTuple = z
|
|
.tuple([z.string().refine(async () => true), z.number().refine(async () => true)])
|
|
.refine(async () => true);
|
|
expectTypeOf<typeof testTuple._output>().toEqualTypeOf<[string, number]>();
|
|
|
|
const val = await testTuple.parseAsync(["asdf", 1234]);
|
|
expect(val).toEqual(val);
|
|
|
|
const r1 = await testTuple.safeParseAsync(["asdf", "asdf"]);
|
|
expect(r1.success).toEqual(false);
|
|
expect(r1.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"expected": "number",
|
|
"code": "invalid_type",
|
|
"path": [
|
|
1
|
|
],
|
|
"message": "Invalid input: expected number, received string"
|
|
}
|
|
]]
|
|
`);
|
|
|
|
const r2 = await testTuple.safeParseAsync(["asdf", 1234, true]);
|
|
expect(r2.success).toEqual(false);
|
|
expect(r2.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"origin": "array",
|
|
"code": "too_big",
|
|
"maximum": 2,
|
|
"path": [],
|
|
"message": "Too big: expected array to have <2 items"
|
|
}
|
|
]]
|
|
`);
|
|
|
|
const r3 = await testTuple.safeParseAsync({});
|
|
expect(r3.success).toEqual(false);
|
|
expect(r3.error!).toMatchInlineSnapshot(`
|
|
[ZodError: [
|
|
{
|
|
"expected": "tuple",
|
|
"code": "invalid_type",
|
|
"path": [],
|
|
"message": "Invalid input: expected tuple, received object"
|
|
}
|
|
]]
|
|
`);
|
|
});
|
|
|
|
test("tuple with optional elements", () => {
|
|
const myTuple = z.tuple([z.string(), z.number().optional(), z.string().optional()]).rest(z.boolean());
|
|
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<[string, number?, string?, ...boolean[]]>();
|
|
|
|
const goodData = [["asdf"], ["asdf", 1234], ["asdf", 1234, "asdf"], ["asdf", 1234, "asdf", true, false, true]];
|
|
for (const data of goodData) {
|
|
expect(myTuple.parse(data)).toEqual(data);
|
|
}
|
|
|
|
const badData = [
|
|
["asdf", "asdf"],
|
|
["asdf", 1234, "asdf", "asdf"],
|
|
["asdf", 1234, "asdf", true, false, "asdf"],
|
|
];
|
|
for (const data of badData) {
|
|
expect(() => myTuple.parse(data)).toThrow();
|
|
}
|
|
});
|
|
|
|
test("tuple with optional elements followed by required", () => {
|
|
const myTuple = z.tuple([z.string(), z.number().optional(), z.string()]).rest(z.boolean());
|
|
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<[string, number | undefined, string, ...boolean[]]>();
|
|
|
|
const goodData = [
|
|
["asdf", 1234, "asdf"],
|
|
["asdf", 1234, "asdf", true, false, true],
|
|
];
|
|
for (const data of goodData) {
|
|
expect(myTuple.parse(data)).toEqual(data);
|
|
}
|
|
|
|
const badData = [
|
|
["asdf"],
|
|
["asdf", 1234],
|
|
["asdf", 1234, "asdf", "asdf"],
|
|
["asdf", 1234, "asdf", true, false, "asdf"],
|
|
];
|
|
for (const data of badData) {
|
|
expect(() => myTuple.parse(data)).toThrow();
|
|
}
|
|
});
|
|
|
|
test("tuple with rest schema", () => {
|
|
const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean());
|
|
expect(myTuple.parse(["asdf", 1234, true, false, true])).toEqual(["asdf", 1234, true, false, true]);
|
|
|
|
expect(myTuple.parse(["asdf", 1234])).toEqual(["asdf", 1234]);
|
|
|
|
expect(() => myTuple.parse(["asdf", 1234, "asdf"])).toThrow();
|
|
type t1 = z.output<typeof myTuple>;
|
|
|
|
expectTypeOf<t1>().toEqualTypeOf<[string, number, ...boolean[]]>();
|
|
});
|
|
|
|
test("sparse array input", () => {
|
|
const schema = z.tuple([z.string(), z.number()]);
|
|
expect(() => schema.parse(new Array(2))).toThrow();
|
|
});
|