When writing tests, validate the actual user-visible behavior and structured error data, not just a substring or a indirectly implied result. Make failures unambiguous (no swallow-pass patterns) and keep tests easy to debug.
Apply this standard:
error.path / error.details when those are part of the contract.try/catch without assertions inside).fatal), add tests that prove the flow stops/continues, not only that an error exists.test.each / equivalent) instead of ad-hoc concatenation.tsd) rather than relying solely on compile-time errors.Example (meaningful runtime assertions):
const result = schema.safeParse(badInput);
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues[0].message).toBe("full expected message");
expect(result.error.issues[0].path).toEqual(['points']);
}
Example (prove fatal stops):
const schema = z
.object({ test: z.literal(true) })
.nullable()
.refine(v => v !== null, { message: 'foo', fatal: true })
.superRefine((v, ctx) => { if (v && (v as any).test) ctx.addIssue({ code: 'custom', message: 'bar' }); });
const out = schema.safeParse(null);
expect(out.success).toBe(false);
expect(out.error.issues.map(i => i.message)).toEqual(['foo']);
Enter the URL of a public GitHub repository