@traversable/zod-test
v0.0.28
Published
<br> <h1 align="center">แฏ๐๐ฟ๐ฎ๐๐ฒ๐ฟ๐๐ฎ๐ฏ๐น๐ฒ/๐๐ผ๐ฑ-๐๐ฒ๐๐</h1> <br>
Readme
Requirements
@traversable/zod-test has 2 peer dependencies:
zod(v4)fast-check
Usage
$ pnpm add -D @traversable/zod-test zod fast-checkHere's an example of importing the library:
import { z } from 'zod'
import { zxTest } from '@traversable/zod-test'
// see below for specifc examplesTrack record
@traversabe/zod-test has found several upstream bugs in zod:
- Security exploit:
z.objectpollutes the globalObjectprototype
- Bug:
z.literalescaping bug
- Bug: "Diagonal" objects passed to
z.enumproduce false negatives
- Bug:
z.fileoutput type incompatible withglobalThis.File
Table of contents
zxTest.fuzzzxTest.seedToSchemazxTest.seedToValidDatazxTest.seedToInvalidDatazxTest.seedToValidDataGeneratorzxTest.seedToInvalidDataGeneratorzxTest.SeedGeneratorzxTest.SeedValidDataGeneratorzxTest.SeedInvalidDataGenerator
zxTest.fuzz
Convert a Zod schema into a fast-check arbitrary.
Configure how fuzzed values will be generated via the 2nd argument (options).
Override individual arbitraries via the 3rd argument (overrides).
[!NOTE]
zxTest.fuzzis the only schema-to-generator function that has itself been fuzz tested to ensure that no matter what schema you give it, the data-generator it returns will always produce valid data.This excludes schemas that make it impossible to generate valid data, for example:
z.neverz.nonoptional(z.undefined())z.enum([])z.union([])z.intersection(z.number(), z.string())
Example
import * as vi from 'vitest'
import * as fc from 'fast-check'
import { fuzz } from '@traversable/zod-test'
const Schema = z.record(
z.string(),
z.union(
z.number(),
z.string(),
)
)
const generator = fuzz(
Schema,
{ record: { minKeys: 1 }, number: { noDefaultInfinity: true } },
{ string: () => fc.stringMatching(/[\S\s]+[\S]+/) },
)
vi.test('fuzz test example', () => {
fc.assert(
fc.property(generator, (data) => {
vi.assert.doesNotThrow(() => Schema.parse(data))
}),
{ numRuns: 1_000 }
)
})See also
- the fast-check docs
zxTest.seedToSchema
Use zxTest.seedToSchema to convert a seed generated by zxTest.SeedGenerator into a
zod schema that satisfies the configuration options you specified.
Example
import { zxTest } from '@traversable/zod-test'
import * as fc from 'fast-check'
const builder = zxTest.SeedGenerator()['*']
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodTypezxTest.seedToValidData
Use zxTest.seedToValidData to convert a seed generated by zxTest.SeedGenerator into
data that satisfies the schema that the seed represents.
Example
import { zxTest } from '@traversable/zod-test'
import * as fc from 'fast-check'
const builder = zxTest.SeedGenerator()['*']
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodType
const validData = zxTest.seedToValidData(mySeed)
mySchema.parse(validData) // will never throwzxTest.seedToInvalidData
Use zxTest.seedToInvalidData to convert a seed generated by zxTest.SeedGenerator into
data that does not satisfy the schema that the seed represents.
Example
import { zxTest } from '@traversable/zod-test'
import * as fc from 'fast-check'
const builder = zxTest.SeedGenerator()['*']
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodType
const invalidData = zxTest.seedToValidData(mySeed)
mySchema.parse(invalidData) // should always throwzxTest.seedToValidDataGenerator
Like zxTest.seedToValidData, except zxTest.seedToValidDataGenerator accepts a seed and returns a valid data arbitrary (which can then be used to produce valid data).
Example
import { zxTest } from '@traversable/zod-test'
import * as fc from 'fast-check'
const builder = zxTest.SeedGenerator()['*']
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodType
const validDataGenerator = zxTest.seedToValidDataGenerator(mySeed)
const [validData] = fc.sample(validDataGenerator, 1)
mySchema.parse(validData) // will never throwzxTest.seedToInvalidDataGenerator
Like zxTest.seedToInvalidData, except zxTest.seedToValidDataGenerator accepts a seed and returns an invalid data arbitrary (which can then be used to produce invalid data).
Example
import type * as z from 'zod'
import * as fc from 'fast-check'
import { zxTest } from '@traversable/zod-test'
const builder = zxTest.SeedGenerator()['*']
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodType
const invalidDataGenerator = zxTest.seedToInvalidDataGenerator(mySeed)
const [invalidData] = fc.sample(invalidDataGenerator, 1)
mySchema.parse(invalidData) // will always throwzxTest.SeedGenerator
[!NOTE]
zxTest.SeedGeneratoris fairly low-level. All of the other exports of this library have been implemented in terms ofzxTest.SeedGenerator.
Generates a configurable, pseudo-random "seed builder".
- Use
zxTest.seedToSchemato convert a seed into a zod schema - Use
zxTest.seedToValidDatato convert a seed into valid data - Use
zxTest.seedToInvalidDatato convert a seed into invalid data
Example
import { zxTest } from '@traversable/zod-test'
import * as fc from 'fast-check'
const builder = zxTest.SeedGenerator({
include: ["boolean", "string", "object"],
// ๐ use `include` to only include certain schema types
exclude: ["boolean", "any"],
// ๐ use `exclude` to exclude certain schema types altogether (overrides `include`)
object: { maxKeys: 5 },
// ๐ specific arbitraries are configurable by name
})
// included schemas are present as properties on your generator...
builder.string
builder.object
// ...excluded schemas are not present...
builder.boolean // ๐ซ TypeError
// ...a special wildcard `"*"` property (pronounced "surprise me") is always present:
builder["*"]
/**
* `fast-check` will generate a seed, which is a data structure containing
* integers that represent a kind of AST.
*
* To use a seed, you need to pass it to an interpreter like `zxTest.seedToSchema`,
* `zxTest.seedToValidData` or `zxTest.seedToInvalidData`:
*/
const [mySeed] = fc.sample(builder.object, 1)
const mySchema = zxTest.seedToSchema(mySeed)
// ^? const mySchema: z.ZodType
const validData = zxTest.seedToValidData(mySeed)
// ^? since the `mySeed` was also used to generate `mySchema`,
// parsing `validData` should always succeed
const invalidData = zxTest.seedToInvalidData(mySeed)
// ^? since the `mySeed` was also used to generate `mySchema`,
// parsing `invalidData` should always failzxTest.SeedValidDataGenerator
Like zxTest.SeedGenerator, except zxTest.SeedValidDataGenerator comes pre-configured to exclude schemas that make it impossible to reliably generate valid data.
[!NOTE]
zxTest.SeedValidDataGeneratordoes not accept any options. If you need more fine-grained control of the schemas being generated, usezxTest.SeedGenerator.
zxTest.SeedInvalidDataGenerator
Like zxTest.SeedGenerator, except zxTest.SeedValidDataGenerator comes pre-configured to exclude schemas that make it impossible to reliably generate invalid data.
[!NOTE]
zxTest.SeedInvalidDataGeneratordoes not accept any options. If you need more fine-grained control of the schemas being generated, usezxTest.SeedGenerator.
