Skip to content

Commit c1ed226

Browse files
committed
test(models): unit test zod validation helpers
1 parent 22ecfb0 commit c1ed226

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import ansis from 'ansis';
2+
import path from 'node:path';
3+
import z, { ZodError } from 'zod';
4+
import { SchemaValidationError, validate } from './validate.js';
5+
6+
describe('validate', () => {
7+
it('should return parsed data if valid', () => {
8+
const configSchema = z
9+
.object({
10+
entry: z.string(),
11+
tsconfig: z.string().default('tsconfig.json'),
12+
})
13+
.meta({ title: 'Config' });
14+
type Config = z.infer<typeof configSchema>;
15+
16+
expect(validate(configSchema, { entry: 'src/main.ts' })).toEqual<Config>({
17+
entry: 'src/main.ts',
18+
tsconfig: 'tsconfig.json',
19+
});
20+
});
21+
22+
it('should throw formatted error if invalid', () => {
23+
const userSchema = z
24+
.object({
25+
name: z.string().min(1),
26+
address: z.string(),
27+
dateOfBirth: z.iso.date().optional(),
28+
})
29+
.meta({ title: 'User' });
30+
type User = z.infer<typeof userSchema>;
31+
32+
expect(() =>
33+
validate(userSchema, { name: '', dateOfBirth: 'Jul 1, 1980' } as User),
34+
).toThrow(`Invalid ${ansis.bold('User')}
35+
✖ Too small: expected string to have >=1 characters
36+
→ at name
37+
✖ Invalid input: expected string, received undefined
38+
→ at address
39+
✖ Invalid ISO date
40+
→ at dateOfBirth`);
41+
});
42+
});
43+
44+
describe('SchemaValidationError', () => {
45+
it('should format ZodError with z.prettifyError', () => {
46+
const error = new ZodError([
47+
{
48+
code: 'invalid_type',
49+
expected: 'string',
50+
input: 42,
51+
message: 'Invalid input: expected string, received number',
52+
path: ['id'],
53+
},
54+
{
55+
code: 'invalid_format',
56+
format: 'datetime',
57+
input: '1980-07-31',
58+
message: 'Invalid ISO datetime',
59+
path: ['logs', 11, 'timestamp'],
60+
},
61+
]);
62+
63+
expect(new SchemaValidationError(error, z.any(), {}).message).toContain(`
64+
✖ Invalid input: expected string, received number
65+
→ at id
66+
✖ Invalid ISO datetime
67+
→ at logs[11].timestamp`);
68+
});
69+
70+
it('should use schema title from meta registry', () => {
71+
const schema = z.number().min(0).max(1).meta({ title: 'Score' });
72+
73+
expect(
74+
new SchemaValidationError(new ZodError([]), schema, {}).message,
75+
).toContain(`Invalid ${ansis.bold('Score')}\n`);
76+
});
77+
78+
it('should use generic message if schema title not in registry', () => {
79+
const schema = z.number().min(0).max(1);
80+
81+
expect(
82+
new SchemaValidationError(new ZodError([]), schema, {}).message,
83+
).toContain('Invalid data\n');
84+
});
85+
86+
it('should include relative file path if provided', () => {
87+
const schema = z.object({}).meta({ title: 'CoreConfig' });
88+
const filePath = path.join(process.cwd(), 'code-pushup.config.ts');
89+
90+
expect(
91+
new SchemaValidationError(new ZodError([]), schema, { filePath }).message,
92+
).toContain(
93+
`Invalid ${ansis.bold('CoreConfig')} in ${ansis.bold('code-pushup.config.ts')} file\n`,
94+
);
95+
});
96+
});

0 commit comments

Comments
 (0)