('#app')!
19 | app.innerHTML = `${JSON.stringify(schema.safeParse(data), null, 2)}`
20 | }
21 |
22 | main()
23 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/union.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 |
7 | export function fakeUnion(
8 | schema: T,
9 | context: Context,
10 | rootFake: typeof internalFake,
11 | ): Infer {
12 | const options = schema._zod.def.options.filter(option => option._zod.def.type !== 'never')
13 | if (options.length === 0) {
14 | options.push(schema._zod.def.options[0])
15 | }
16 | return rootFake(getFaker().helpers.arrayElement(options), context)
17 | }
18 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/tuple.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 |
7 | export function fakeTuple(
8 | schema: T,
9 | context: Context,
10 | rootFake: typeof internalFake,
11 | ): Infer {
12 | return schema._zod.def.items
13 | .map(item => rootFake(item, context))
14 | .concat(
15 | schema._zod.def.rest
16 | ? getFaker().helpers.multiple(() => rootFake(schema._zod.def.rest!, context), { count: { min: 0, max: 5 } })
17 | : [],
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/examples/v4/src/main.ts:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker'
2 | import { fake, setFaker } from 'zod-schema-faker/v4'
3 | import { z } from 'zod/mini'
4 |
5 | const main = async () => {
6 | const schema = z.uuid()
7 | let data: string
8 |
9 | if (process.env.NODE_ENV !== 'production') {
10 | setFaker(faker)
11 |
12 | data = fake(schema)
13 | } else {
14 | data = await fetch('https://httpbin.org/uuid')
15 | .then(response => response.json())
16 | .then(json => json.uuid)
17 | }
18 |
19 | const app = document.querySelector('#app')!
20 | app.innerHTML = `${JSON.stringify(schema.safeParse(data), null, 2)}`
21 | }
22 |
23 | main()
24 |
--------------------------------------------------------------------------------
/src/v3/utils.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { ZodSchemaFakerError } from './error'
3 |
4 | export function assertsZodSchema(schema: unknown): asserts schema is z.ZodTypeAny {
5 | if (
6 | typeof schema !== 'object' ||
7 | schema === null ||
8 | '_parse' in schema === false ||
9 | typeof schema._parse !== 'function'
10 | ) {
11 | throw new ZodSchemaFakerError(`Expected a zod schema, but got ${schema}`)
12 | }
13 | }
14 |
15 | export function lcm(a: T, b: T): T {
16 | return ((a * b) / gcd(a, b)) as T
17 | }
18 |
19 | export function gcd(a: T, b: T): T {
20 | return b === 0n || b === 0 ? a : gcd(b, (a % b) as T)
21 | }
22 |
--------------------------------------------------------------------------------
/tests/v3/fake.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from 'vitest'
2 | import { z } from 'zod/v3'
3 | import { fake, install } from '../../src/v3'
4 | import { uninstall } from '../../src/v3/installation'
5 |
6 | describe('fake', () => {
7 | test('fake is a function', () => {
8 | expect(typeof fake).toBe('function')
9 | })
10 |
11 | test('fake should assert parameters', () => {
12 | expect(() => fake(undefined as any)).toThrow()
13 | })
14 |
15 | test('fake should accepts a ZodType schema', () => {
16 | install()
17 | expect(() => fake(z.number())).not.toThrow()
18 | uninstall()
19 | })
20 |
21 | test('fake should throw an error if not installed', () => {
22 | expect(() => fake(z.number())).toThrow()
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/tests/v3/util.ts:
--------------------------------------------------------------------------------
1 | import { test } from 'vitest'
2 |
3 | const count = 50
4 |
5 | interface TestMultipleTimes {
6 | (name: string, fn: () => void): void
7 | only(name: string, fn: () => void): void
8 | skip(name: string, fn: () => void): void
9 | }
10 |
11 | export const testMultipleTimes: TestMultipleTimes = (name, fn) => {
12 | test(name, () => {
13 | for (let i = 0; i < count; i++) {
14 | fn()
15 | }
16 | })
17 | }
18 |
19 | testMultipleTimes.only = (name, fn) => {
20 | test.only(name, () => {
21 | for (let i = 0; i < count; i++) {
22 | fn()
23 | }
24 | })
25 | }
26 |
27 | testMultipleTimes.skip = (name, fn) => {
28 | test.skip(name, () => {
29 | for (let i = 0; i < count; i++) {
30 | fn()
31 | }
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/src/v3/zod-any-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { fake } from './fake'
3 | import { getFaker } from './random'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | const schemas = (() => {
7 | const simpleSchemas = [z.string(), z.number(), z.boolean(), z.null()]
8 | const arraySchemas = simpleSchemas.map(schema => z.array(schema))
9 | const objectSchemas = simpleSchemas.map(schema =>
10 | z.object({
11 | foo: schema,
12 | }),
13 | )
14 |
15 | return [...simpleSchemas, ...arraySchemas, ...objectSchemas]
16 | })()
17 |
18 | export class ZodAnyFaker extends ZodTypeFaker {
19 | fake(): z.infer {
20 | const randomSchema = getFaker().helpers.arrayElement(schemas)
21 | return fake(randomSchema)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/v3/zod-record-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { ZodSchemaFakerError } from './error'
3 | import { fake } from './fake'
4 | import { getFaker } from './random'
5 | import { ZodTypeFaker } from './zod-type-faker'
6 |
7 | export class ZodRecordFaker> extends ZodTypeFaker {
8 | fake(): z.infer {
9 | if (this.schema._def.keyType instanceof z.ZodString === false) {
10 | throw new ZodSchemaFakerError('Invalid record key type: In runtime JavaScript, all keys are strings.')
11 | }
12 |
13 | return Object.fromEntries(
14 | getFaker().helpers.multiple(() => [fake(this.schema._def.keyType), fake(this.schema._def.valueType)], {
15 | count: { min: 0, max: 10 },
16 | }),
17 | )
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/v3/zod-set-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { fake } from './fake'
3 | import { getFaker } from './random'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | export class ZodSetFaker> extends ZodTypeFaker {
7 | fake(): z.infer {
8 | const min = this.schema._def.minSize?.value ?? 0
9 | const max = this.schema._def.maxSize?.value ?? getFaker().number.int({ min, max: min + 10 })
10 |
11 | if (min > max) {
12 | throw new RangeError()
13 | }
14 |
15 | const set = new Set()
16 | while (set.size < min) {
17 | set.add(fake(this.schema._def.valueType))
18 | }
19 | while (set.size < max && getFaker().datatype.boolean()) {
20 | set.add(fake(this.schema._def.valueType))
21 | }
22 | return set
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/v3/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from 'vitest'
2 | import { z } from 'zod/v3'
3 | import { assertsZodSchema } from '../../src/v3/utils'
4 |
5 | test('assertsZodSchema should throw an error if schema is not a zod schema', () => {
6 | expect(() => assertsZodSchema(null)).toThrow()
7 | expect(() => assertsZodSchema(undefined)).toThrow()
8 | expect(() => assertsZodSchema(42)).toThrow()
9 | expect(() => assertsZodSchema('foo')).toThrow()
10 | expect(() => assertsZodSchema({})).toThrow()
11 | })
12 |
13 | test('assertsZodSchema should not throw an error if schema is a zod schema', () => {
14 | expect(() => assertsZodSchema(z.null())).not.toThrow()
15 | expect(() => assertsZodSchema(z.undefined())).not.toThrow()
16 | expect(() => assertsZodSchema(z.number())).not.toThrow()
17 | expect(() => assertsZodSchema(z.string())).not.toThrow()
18 | expect(() => assertsZodSchema(z.object({}))).not.toThrow()
19 | })
20 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/object.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 |
7 | export function fakeObject(
8 | schema: T,
9 | context: Context,
10 | rootFake: typeof internalFake,
11 | ): Infer {
12 | return Object.fromEntries(
13 | Object.entries(schema._zod.def.shape)
14 | .concat(
15 | schema._zod.def.catchall && schema._zod.def.catchall._zod.def.type !== 'never'
16 | ? getFaker()
17 | .helpers.multiple(() => getFaker().string.uuid())
18 | .filter(key => !schema._zod.def.shape[key])
19 | .map(key => [key, schema._zod.def.catchall!])
20 | : [],
21 | )
22 | .map(([key, value]) => [key, rootFake(value, { ...context, depth: context.depth + 1 })]),
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "allowSyntheticDefaultImports": true,
11 | "moduleResolution": "node",
12 | "isolatedModules": true,
13 | "isolatedDeclarations": true,
14 | "noEmit": true,
15 | "declaration": true,
16 | "esModuleInterop": true,
17 |
18 | /* Linting */
19 | "strict": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "strictBindCallApply": true,
22 | "strictNullChecks": true,
23 | "strictFunctionTypes": true,
24 | "strictPropertyInitialization": true,
25 | "stripInternal": true,
26 | "noImplicitAny": true,
27 | "noImplicitOverride": true,
28 | "noImplicitReturns": true,
29 | "noImplicitThis": true
30 | },
31 | "include": ["src", "tests"]
32 | }
33 |
--------------------------------------------------------------------------------
/src/v3/zod-effects-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { fake } from './fake'
3 | import { ZodTypeFaker } from './zod-type-faker'
4 |
5 | export class ZodEffectsFaker> extends ZodTypeFaker {
6 | fake(): z.infer {
7 | let result: any
8 | switch (this.schema._def.effect.type) {
9 | case 'preprocess':
10 | result = fake(this.schema._def.schema)
11 | break
12 |
13 | case 'refinement':
14 | result = fake(this.schema._def.schema)
15 | break
16 |
17 | case 'transform':
18 | result = this.schema._def.effect.transform(fake(this.schema._def.schema), {
19 | /* v8 ignore next 1 */
20 | addIssue: () => void 0,
21 | path: [],
22 | })
23 | break
24 |
25 | /* v8 ignore next 3 */
26 | default: {
27 | const _: never = this.schema._def.effect
28 | }
29 | }
30 |
31 | return result
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/pipe.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 |
7 | const truthyValues = ['true', '1', 'yes', 'on', 'y', 'enabled']
8 | const falsyValues = ['false', '0', 'no', 'off', 'n', 'disabled']
9 | const stringBoolValues = [...truthyValues, ...falsyValues]
10 |
11 | export function fakePipe(
12 | schema: T,
13 | context: Context,
14 | rootFake: typeof internalFake,
15 | ): Infer {
16 | if (schema._zod.def.out._zod.def.type === 'boolean') {
17 | return getFaker().helpers.arrayElement(stringBoolValues)
18 | }
19 |
20 | const left = rootFake(schema._zod.def.in, context) as any
21 | const payload = { value: left, issues: left.issues }
22 | const _context = {}
23 | const right = schema._zod.def.out._zod.run(payload, _context)
24 | payload.value = right
25 | return left
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ernest
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/record.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 |
7 | export function fakeRecord(
8 | schema: T,
9 | context: Context,
10 | rootFake: typeof internalFake,
11 | ): Infer {
12 | if (schema._zod.def.keyType instanceof core.$ZodEnum) {
13 | return Object.fromEntries(
14 | Object.values(schema._zod.def.keyType._zod.def.entries).map(key => [
15 | key,
16 | rootFake(schema._zod.def.valueType, context),
17 | ]),
18 | )
19 | } else if (schema._zod.def.keyType instanceof core.$ZodLiteral) {
20 | return Object.fromEntries(
21 | schema._zod.def.keyType._zod.def.values.map(key => [key, rootFake(schema._zod.def.valueType, context)]),
22 | )
23 | } else {
24 | return Object.fromEntries(
25 | getFaker().helpers.multiple(() => [
26 | rootFake(schema._zod.def.keyType, context),
27 | rootFake(schema._zod.def.valueType, context),
28 | ]),
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/v4/internals/random.ts:
--------------------------------------------------------------------------------
1 | import { Faker, SimpleFaker } from '@faker-js/faker'
2 | import RandExp from 'randexp'
3 |
4 | let _faker: Faker
5 |
6 | /**
7 | * Set the faker instance to use.
8 | */
9 | export function setFaker(faker: Faker): void {
10 | _faker = faker
11 | }
12 |
13 | /**
14 | * Get the faker instance.
15 | */
16 | export function getFaker(): Faker {
17 | if (_faker) {
18 | return _faker
19 | } else {
20 | throw ReferenceError('Faker instance not set. Use `setFaker` to set it.')
21 | }
22 | }
23 |
24 | const _simpleFaker = new SimpleFaker()
25 | /**
26 | * Create random strings that match a given regular expression.
27 | */
28 | export const randexp = (pattern: string | RegExp, flags?: string): string => {
29 | const randexp = new RandExp(pattern, flags)
30 | randexp.randInt = (from, to) => _simpleFaker.number.int({ min: from, max: to })
31 | return randexp.gen()
32 | }
33 |
34 | /**
35 | * Sets the seed or generates a new one.
36 | *
37 | * This method is intended to allow for consistent values in tests, so you might want to use hardcoded values as the seed.
38 | */
39 | export const seed = (value?: number): void => {
40 | _faker.seed(value)
41 | _simpleFaker.seed(value)
42 | }
43 |
--------------------------------------------------------------------------------
/src/v3/zod-array-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { fake } from './fake'
3 | import { getFaker } from './random'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | export class ZodArrayFaker> extends ZodTypeFaker {
7 | fake(): z.infer {
8 | if (this.schema._def.exactLength !== null) {
9 | if (
10 | this.schema._def.minLength !== null &&
11 | this.schema._def.minLength.value !== this.schema._def.exactLength.value
12 | ) {
13 | throw new RangeError()
14 | }
15 | if (
16 | this.schema._def.maxLength !== null &&
17 | this.schema._def.maxLength.value !== this.schema._def.exactLength.value
18 | ) {
19 | throw new RangeError()
20 | }
21 | }
22 | const min = this.schema._def.exactLength?.value ?? this.schema._def.minLength?.value ?? 0
23 | const max =
24 | this.schema._def.exactLength?.value ??
25 | this.schema._def.maxLength?.value ??
26 | getFaker().number.int({ min, max: min + 2 })
27 | if (min > max) {
28 | throw new RangeError()
29 | }
30 | return getFaker().helpers.multiple(() => fake(this.schema._def.type), { count: { min, max } })
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/v3/fake.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { ZodSchemaFakerError } from './error'
3 | import { ZodTypeFakerConcrete } from './zod-type-faker'
4 |
5 | export const zodFirstPartyTypeKindToZodTypeFaker: Map<
6 | z.ZodFirstPartyTypeKind,
7 | typeof ZodTypeFakerConcrete
8 | > = new Map()
9 | export const zodTypeToZodTypeFaker: Map> = new Map()
10 |
11 | /**
12 | * Generate fake data based on schema.
13 | *
14 | * @throws when a corresponding faker is not registered.
15 | */
16 | export const fake = (schema: T): z.infer => {
17 | const typeName = (schema._def as any).typeName
18 | const Faker = zodTypeToZodTypeFaker.get(schema) ?? zodFirstPartyTypeKindToZodTypeFaker.get(typeName)
19 | if (Faker === undefined) {
20 | throw new ZodSchemaFakerError(`Unsupported schema type: ${typeName}.
21 | - If this is a custom schema, you may not have installed a corresponding faker. If you need help with installation, please refer to the documentation for more information.
22 | - If this is a built-in schema, it may not be implemented yet. Please file an issue to let us know: https://github.com/soc221b/zod-schema-faker/issues`)
23 | }
24 |
25 | return new Faker(schema).fake()
26 | }
27 |
--------------------------------------------------------------------------------
/tests/v3/zod-never-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodNeverFaker } from '../../src/v3/zod-never-faker'
5 |
6 | test('ZodNeverFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodNeverFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodNeverFaker should accepts a ZodNever schema', () => {
12 | const schema = z.never()
13 | expect(() => new ZodNeverFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodNeverFaker should return a ZodNeverFaker instance', () => {
17 | const schema = z.never()
18 | const faker = new ZodNeverFaker(schema)
19 | expect(faker instanceof ZodNeverFaker).toBe(true)
20 | })
21 |
22 | test('ZodNeverFaker.fake should be a function', () => {
23 | const schema = z.never()
24 | const faker = new ZodNeverFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodNeverFaker.fake should return never type', () => {
29 | const schema = z.never()
30 | const faker = new ZodNeverFaker(schema)
31 | expectType, never>>(true)
32 | })
33 |
34 | test('ZodNullFaker.fake should throw an error', () => {
35 | const schema = z.never()
36 | const faker = new ZodNeverFaker(schema)
37 | expect(() => faker.fake()).toThrow()
38 | })
39 |
--------------------------------------------------------------------------------
/tests/v3/zod-nan-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodNaNFaker } from '../../src/v3/zod-nan-faker'
5 |
6 | test('ZodNaNFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodNaNFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodNaNFaker should accepts a ZodNaN schema', () => {
12 | const schema = z.nan()
13 | expect(() => new ZodNaNFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodNaNFaker should return a ZodNaNFaker instance', () => {
17 | const schema = z.nan()
18 | const faker = new ZodNaNFaker(schema)
19 | expect(faker instanceof ZodNaNFaker).toBe(true)
20 | })
21 |
22 | test('ZodNaNFaker.fake should be a function', () => {
23 | const schema = z.nan()
24 | const faker = new ZodNaNFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodNaNFaker.fake should return number type', () => {
29 | const schema = z.nan()
30 | const faker = new ZodNaNFaker(schema)
31 | expectType, number>>(true)
32 | })
33 |
34 | test('ZodNaNFaker.fake should return a valid data', () => {
35 | const schema = z.nan()
36 | const faker = new ZodNaNFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/tests/v3/zod-instanceof-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeEach, expect, test } from 'vitest'
2 | import { z } from 'zod/v3'
3 | import { fake, getFaker, install, installCustom, ZodTypeFaker } from '../../src/v3'
4 |
5 | interface UserLike {
6 | name: string
7 | }
8 |
9 | class User implements UserLike {
10 | constructor(public name: string) {}
11 | }
12 |
13 | // 1/5. define custom schema
14 | const UserSchema = z.instanceof(User).and(z.object({ name: z.string() }).strict())
15 |
16 | // 2/5. define custom faker
17 | class UserFaker extends ZodTypeFaker {
18 | fake(): User {
19 | return new User(`${getFaker().person.firstName()}`)
20 | }
21 | }
22 |
23 | beforeEach(() => {
24 | // 3/5. install basic faker
25 | install()
26 | // 4/5. install custom faker
27 | installCustom(UserSchema, UserFaker)
28 | })
29 |
30 | test('instanceof', () => {
31 | // 5/5. use it
32 | const data = fake(UserSchema)
33 | expect(UserSchema.safeParse(data).success).toBe(true)
34 |
35 | const userLike: UserLike = { name: 'foo' }
36 | const user: User = new User('bar')
37 | expect(UserSchema.safeParse(user).data).toEqual(user)
38 | expect(UserSchema.safeParse(userLike).error).toMatchInlineSnapshot(`
39 | [ZodError: [
40 | {
41 | "code": "custom",
42 | "message": "Input not instance of User",
43 | "fatal": true,
44 | "path": []
45 | }
46 | ]]
47 | `)
48 | })
49 |
--------------------------------------------------------------------------------
/examples/v4/src/typescript.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/v3/zod-null-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodNullFaker } from '../../src/v3/zod-null-faker'
5 |
6 | test('ZodNullFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodNullFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodNullFaker should accepts a ZodNull schema', () => {
12 | const schema = z.null()
13 | expect(() => new ZodNullFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodNullFaker should return a ZodNullFaker instance', () => {
17 | const schema = z.null()
18 | const faker = new ZodNullFaker(schema)
19 | expect(faker instanceof ZodNullFaker).toBe(true)
20 | })
21 |
22 | test('ZodNullFaker.fake should be a function', () => {
23 | const schema = z.null()
24 | const faker = new ZodNullFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodNullFaker.fake should return null type', () => {
29 | const schema = z.null()
30 | const faker = new ZodNullFaker(schema)
31 | expectType, null>>(true)
32 | })
33 |
34 | test('ZodNullFaker.fake should return a valid data', () => {
35 | const schema = z.null()
36 | const faker = new ZodNullFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/tests/v3/zod-custom-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeEach, expect, test } from 'vitest'
2 | import { z } from 'zod/v3'
3 | import { fake, getFaker, install, installCustom, ZodTypeFaker } from '../../src/v3'
4 |
5 | // 1/5. define custom schema
6 | const pxSchema = z.custom<`${number}px`>(val => {
7 | return typeof val === 'string' ? /^\d+px$/.test(val) : false
8 | })
9 |
10 | // 2/5. define custom faker
11 | class ZodPxFaker extends ZodTypeFaker {
12 | fake(): `${number}px` {
13 | // you can use `getFaker` to generate fake data
14 | return `${getFaker().number.int({ min: 0 })}px`
15 | // or use `randexp` if applicable
16 | // return randexp(/[1-9]\d+?px/) as `${number}px`
17 | }
18 | }
19 |
20 | beforeEach(() => {
21 | // 3/5. install basic faker
22 | install()
23 | // 4/5. install custom faker
24 | installCustom(pxSchema, ZodPxFaker)
25 | })
26 |
27 | test('basic', () => {
28 | // 5/5. use it
29 | const data = fake(pxSchema)
30 |
31 | expect(pxSchema.safeParse(data).success).toBe(true)
32 | })
33 |
34 | test('integration', () => {
35 | const schema = z
36 | .object({
37 | padding: pxSchema,
38 | })
39 | .strict()
40 |
41 | const data = fake(schema)
42 |
43 | expect(schema.safeParse(data).success).toBe(true)
44 | })
45 |
46 | test('type', () => {
47 | // @ts-expect-error
48 | installCustom(z.custom(), ZodTypeFaker)
49 |
50 | expect(true).toBe(true)
51 | })
52 |
--------------------------------------------------------------------------------
/tests/v3/zod-any-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodAnyFaker } from '../../src/v3/zod-any-faker'
6 |
7 | test('ZodAnyFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodAnyFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodAnyFaker should accepts a ZodAny schema', () => {
13 | const schema = z.any()
14 | expect(() => new ZodAnyFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodAnyFaker should return a ZodAnyFaker instance', () => {
18 | const schema = z.any()
19 | const faker = new ZodAnyFaker(schema)
20 | expect(faker instanceof ZodAnyFaker).toBe(true)
21 | })
22 |
23 | test('ZodAnyFaker.fake should be a function', () => {
24 | const schema = z.any()
25 | const faker = new ZodAnyFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodAnyFaker.fake should return any type', () => {
30 | const schema = z.any()
31 | const faker = new ZodAnyFaker(schema)
32 | expectType, any>>(true)
33 | })
34 |
35 | test('ZodAnyFaker.fake should return a valid data', () => {
36 | install()
37 | const schema = z.any()
38 | const faker = new ZodAnyFaker(schema)
39 | const data = faker.fake()
40 | expect(schema.safeParse(data).success).toBe(true)
41 | })
42 |
--------------------------------------------------------------------------------
/examples/v4/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/v3/zod-void-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodVoidFaker } from '../../src/v3/zod-void-faker'
6 |
7 | test('ZodVoidFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodVoidFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodVoidFaker should accepts a ZodVoid schema', () => {
13 | const schema = z.void()
14 | expect(() => new ZodVoidFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodVoidFaker should return a ZodVoidFaker instance', () => {
18 | const schema = z.void()
19 | const faker = new ZodVoidFaker(schema)
20 | expect(faker instanceof ZodVoidFaker).toBe(true)
21 | })
22 |
23 | test('ZodVoidFaker.fake should be a function', () => {
24 | const schema = z.void()
25 | const faker = new ZodVoidFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodVoidFaker.fake should return void type', () => {
30 | const schema = z.void()
31 | const faker = new ZodVoidFaker(schema)
32 | expectType, void>>(true)
33 | })
34 |
35 | test('ZodVoidFaker.fake should return a valid data', () => {
36 | install()
37 | const schema = z.void()
38 | const faker = new ZodVoidFaker(schema)
39 | const data = faker.fake()
40 | expect(schema.safeParse(data).success).toBe(true)
41 | })
42 |
--------------------------------------------------------------------------------
/tests/v3/zod-symbol-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodSymbolFaker } from '../../src/v3/zod-symbol-faker'
5 |
6 | test('ZodSymbolFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodSymbolFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodSymbolFaker should accepts a ZodSymbol schema', () => {
12 | const schema = z.symbol()
13 | expect(() => new ZodSymbolFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodSymbolFaker should return a ZodSymbolFaker instance', () => {
17 | const schema = z.symbol()
18 | const faker = new ZodSymbolFaker(schema)
19 | expect(faker instanceof ZodSymbolFaker).toBe(true)
20 | })
21 |
22 | test('ZodSymbolFaker.fake should be a function', () => {
23 | const schema = z.symbol()
24 | const faker = new ZodSymbolFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodSymbolFaker.fake should return the given type', () => {
29 | const schema = z.symbol()
30 | const faker = new ZodSymbolFaker(schema)
31 | expectType, z.infer>>(true)
32 | })
33 |
34 | test('ZodSymbolFaker.fake should return a valid data', () => {
35 | const schema = z.symbol()
36 | const faker = new ZodSymbolFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/tests/v3/zod-boolean-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodBooleanFaker } from '../../src/v3/zod-boolean-faker'
5 |
6 | test('ZodBooleanFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodBooleanFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodBooleanFaker should accepts a ZodBoolean schema', () => {
12 | const schema = z.boolean()
13 | expect(() => new ZodBooleanFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodBooleanFaker should return a ZodBooleanFaker instance', () => {
17 | const schema = z.boolean()
18 | const faker = new ZodBooleanFaker(schema)
19 | expect(faker instanceof ZodBooleanFaker).toBe(true)
20 | })
21 |
22 | test('ZodBooleanFaker.fake should be a function', () => {
23 | const schema = z.boolean()
24 | const faker = new ZodBooleanFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodBooleanFaker.fake should return boolean type', () => {
29 | const schema = z.boolean()
30 | const faker = new ZodBooleanFaker(schema)
31 | expectType, boolean>>(true)
32 | })
33 |
34 | test('ZodBooleanFaker.fake should return a valid data', () => {
35 | const schema = z.boolean()
36 | const faker = new ZodBooleanFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/tests/v3/zod-literal-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodLiteralFaker } from '../../src/v3/zod-literal-faker'
5 |
6 | test('ZodLiteralFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodLiteralFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodLiteralFaker should accepts a ZodLiteral schema', () => {
12 | const schema = z.literal('foo')
13 | expect(() => new ZodLiteralFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodLiteralFaker should return a ZodLiteralFaker instance', () => {
17 | const schema = z.literal('foo')
18 | const faker = new ZodLiteralFaker(schema)
19 | expect(faker instanceof ZodLiteralFaker).toBe(true)
20 | })
21 |
22 | test('ZodLiteralFaker.fake should be a function', () => {
23 | const schema = z.literal('foo')
24 | const faker = new ZodLiteralFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodLiteralFaker.fake should return the given type', () => {
29 | const schema = z.literal('foo')
30 | const faker = new ZodLiteralFaker(schema)
31 | expectType, 'foo'>>(true)
32 | })
33 |
34 | test('ZodLiteralFaker.fake should return a valid data', () => {
35 | const schema = z.literal('foo')
36 | const faker = new ZodLiteralFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/tests/v3/zod-undefined-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodUndefinedFaker } from '../../src/v3/zod-undefined-faker'
5 |
6 | test('ZodUndefinedFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodUndefinedFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodUndefinedFaker should accepts a ZodUndefined schema', () => {
12 | const schema = z.undefined()
13 | expect(() => new ZodUndefinedFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodUndefinedFaker should return a ZodUndefinedFaker instance', () => {
17 | const schema = z.undefined()
18 | const faker = new ZodUndefinedFaker(schema)
19 | expect(faker instanceof ZodUndefinedFaker).toBe(true)
20 | })
21 |
22 | test('ZodUndefinedFaker.fake should be a function', () => {
23 | const schema = z.undefined()
24 | const faker = new ZodUndefinedFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodUndefinedFaker.fake should return undefined type', () => {
29 | const schema = z.undefined()
30 | const faker = new ZodUndefinedFaker(schema)
31 | expectType, undefined>>(true)
32 | })
33 |
34 | test('ZodUndefinedFaker.fake should return a valid data', () => {
35 | const schema = z.undefined()
36 | const faker = new ZodUndefinedFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
--------------------------------------------------------------------------------
/src/v3/zod-date-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { getFaker } from './random'
3 | import { ZodTypeFaker } from './zod-type-faker'
4 |
5 | export const minDateValue = -8640000000000000
6 | export const maxDateValue = 8640000000000000
7 |
8 | export class ZodDateFaker extends ZodTypeFaker {
9 | fake(): z.infer {
10 | let min: undefined | number = undefined
11 | let max: undefined | number = undefined
12 | for (const check of this.schema._def.checks) {
13 | switch (check.kind) {
14 | case 'min': {
15 | const _min = check.value
16 | min = min !== undefined ? Math.max(min, _min) : _min
17 | break
18 | }
19 | case 'max': {
20 | const _max = check.value
21 | max = max !== undefined ? Math.min(max, _max) : _max
22 | break
23 | }
24 | /* v8 ignore next 3 */
25 | default: {
26 | const _: never = check
27 | }
28 | }
29 | }
30 | if (min === undefined) {
31 | if (getFaker().datatype.boolean({ probability: 0.2 })) {
32 | min = minDateValue
33 | } else {
34 | min = (max ?? new Date('2025-01-01T00:00:00.000Z').getTime()) - 31536000000
35 | }
36 | }
37 | if (max === undefined) {
38 | if (getFaker().datatype.boolean({ probability: 0.2 })) {
39 | max = maxDateValue
40 | } else {
41 | max = min + 31536000000
42 | }
43 | }
44 |
45 | return getFaker().date.between({ from: min, to: max })
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/v3/zod-unknown-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodUnknownFaker } from '../../src/v3/zod-unknown-faker'
6 |
7 | test('ZodUnknownFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodUnknownFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodUnknownFaker should accepts a ZodUnknown schema', () => {
13 | const schema = z.unknown()
14 | expect(() => new ZodUnknownFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodUnknownFaker should return a ZodUnknownFaker instance', () => {
18 | const schema = z.unknown()
19 | const faker = new ZodUnknownFaker(schema)
20 | expect(faker instanceof ZodUnknownFaker).toBe(true)
21 | })
22 |
23 | test('ZodUnknownFaker.fake should be a function', () => {
24 | const schema = z.unknown()
25 | const faker = new ZodUnknownFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodUnknownFaker.fake should return unknown type', () => {
30 | const schema = z.unknown()
31 | const faker = new ZodUnknownFaker(schema)
32 | expectType, unknown>>(true)
33 | })
34 |
35 | test('ZodUnknownFaker.fake should return a valid data', () => {
36 | install()
37 | const schema = z.unknown()
38 | const faker = new ZodUnknownFaker(schema)
39 | const data = faker.fake()
40 | expect(schema.safeParse(data).success).toBe(true)
41 | })
42 |
--------------------------------------------------------------------------------
/examples/v3/favicon.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/tests/v3/zod-map-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodMapFaker } from '../../src/v3/zod-map-faker'
6 |
7 | test('ZodMapFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodMapFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodMapFaker should accepts a ZodMap schema', () => {
13 | const schema = z.map(z.number(), z.string())
14 | expect(() => new ZodMapFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodMapFaker should return a ZodMapFaker instance', () => {
18 | const schema = z.map(z.number(), z.string())
19 | const faker = new ZodMapFaker(schema)
20 | expect(faker instanceof ZodMapFaker).toBe(true)
21 | })
22 |
23 | test('ZodMapFaker.fake should be a function', () => {
24 | const schema = z.map(z.number(), z.string())
25 | const faker = new ZodMapFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodMapFaker.fake should return Map type', () => {
30 | const schema = z.map(z.number(), z.string())
31 | const faker = new ZodMapFaker(schema)
32 | expectType, Map>>(true)
33 | })
34 |
35 | test('ZodMapFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.map(z.number(), z.string())
39 | const faker = new ZodMapFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
--------------------------------------------------------------------------------
/src/v3/zod-object-faker.ts:
--------------------------------------------------------------------------------
1 | import { UnknownKeysParam, z } from 'zod/v3'
2 | import { fake } from './fake'
3 | import { getFaker } from './random'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | export class ZodObjectFaker> extends ZodTypeFaker {
7 | fake(): z.infer {
8 | const result = {} as any
9 |
10 | const catchall = this.schema._def.catchall
11 | const unknownKeys = this.schema._def.unknownKeys as UnknownKeysParam
12 | if (catchall instanceof z.ZodNever) {
13 | switch (unknownKeys) {
14 | case 'passthrough': {
15 | Object.assign(
16 | result,
17 | Object.fromEntries(
18 | getFaker().helpers.multiple(() => [fake(z.string().regex(/^extra_[a-z]{5}$/)), fake(z.any())], {
19 | count: { min: 0, max: 5 },
20 | }),
21 | ),
22 | )
23 | break
24 | }
25 | default: {
26 | const _: 'strip' | 'strict' = unknownKeys
27 | }
28 | }
29 | } else {
30 | Object.assign(
31 | result,
32 | Object.fromEntries(
33 | getFaker().helpers.multiple(() => [fake(z.string().regex(/^extra_[a-z]{5}$/)), fake(catchall)], {
34 | count: { min: 0, max: 5 },
35 | }),
36 | ),
37 | )
38 | }
39 |
40 | const shape = this.schema._def.shape()
41 | const keys = Object.keys(shape)
42 | for (const key of keys) {
43 | const value = fake(shape[key])
44 | result[key] = value
45 | }
46 |
47 | return result
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/v3/zod-nullable-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodNullableFaker } from '../../src/v3/zod-nullable-faker'
6 |
7 | test('ZodNullableFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodNullableFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodNullableFaker should accepts a ZodNullable schema', () => {
13 | const schema = z.nullable(z.string())
14 | expect(() => new ZodNullableFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodNullableFaker should return a ZodNullableFaker instance', () => {
18 | const schema = z.nullable(z.string())
19 | const faker = new ZodNullableFaker(schema)
20 | expect(faker instanceof ZodNullableFaker).toBe(true)
21 | })
22 |
23 | test('ZodNullableFaker.fake should be a function', () => {
24 | const schema = z.nullable(z.string())
25 | const faker = new ZodNullableFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodNullableFaker.fake should return nullable type', () => {
30 | const schema = z.nullable(z.string())
31 | const faker = new ZodNullableFaker(schema)
32 | expectType, string | null>>(true)
33 | })
34 |
35 | test('ZodNullableFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.nullable(z.string())
39 | const faker = new ZodNullableFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
--------------------------------------------------------------------------------
/tests/v3/zod-union-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodUnionFaker } from '../../src/v3/zod-union-faker'
6 |
7 | test('ZodUnionFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodUnionFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodUnionFaker should accepts a ZodUnion schema', () => {
13 | const schema = z.union([z.number(), z.string()])
14 | expect(() => new ZodUnionFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodUnionFaker should return a ZodUnionFaker instance', () => {
18 | const schema = z.union([z.number(), z.string()])
19 | const faker = new ZodUnionFaker(schema)
20 | expect(faker instanceof ZodUnionFaker).toBe(true)
21 | })
22 |
23 | test('ZodUnionFaker.fake should be a function', () => {
24 | const schema = z.union([z.number(), z.string()])
25 | const faker = new ZodUnionFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodUnionFaker.fake should return union type', () => {
30 | const schema = z.union([z.number(), z.string()])
31 | const faker = new ZodUnionFaker(schema)
32 | expectType, number | string>>(true)
33 | })
34 |
35 | test('ZodUnionFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.union([z.number(), z.string()])
39 | const faker = new ZodUnionFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
--------------------------------------------------------------------------------
/tests/v3/zod-optional-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodOptionalFaker } from '../../src/v3/zod-optional-faker'
6 |
7 | test('ZodOptionalFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodOptionalFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodOptionalFaker should accepts a ZodOptional schema', () => {
13 | const schema = z.optional(z.string())
14 | expect(() => new ZodOptionalFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodOptionalFaker should return a ZodOptionalFaker instance', () => {
18 | const schema = z.optional(z.string())
19 | const faker = new ZodOptionalFaker(schema)
20 | expect(faker instanceof ZodOptionalFaker).toBe(true)
21 | })
22 |
23 | test('ZodOptionalFaker.fake should be a function', () => {
24 | const schema = z.optional(z.string())
25 | const faker = new ZodOptionalFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodOptionalFaker.fake should return optional type', () => {
30 | const schema = z.optional(z.string())
31 | const faker = new ZodOptionalFaker(schema)
32 | expectType, string | undefined>>(true)
33 | })
34 |
35 | test('ZodOptionalFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.optional(z.string())
39 | const faker = new ZodOptionalFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/set.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { MAX_DEPTH } from '../config'
3 | import { Context } from '../context'
4 | import { rootFake as internalFake } from '../fake'
5 | import { getFaker } from '../random'
6 | import { Infer } from '../type'
7 |
8 | export function fakeSet(schema: T, context: Context, rootFake: typeof internalFake): Infer {
9 | let min = 0
10 | let max = Infinity
11 | for (const check of (schema._zod.def.checks ?? []) as core.$ZodChecks[]) {
12 | switch (check._zod.def.check) {
13 | case 'max_size': {
14 | max = Math.min(max, check._zod.def.maximum)
15 | break
16 | }
17 | case 'min_size': {
18 | min = Math.max(min, check._zod.def.minimum)
19 | break
20 | }
21 | case 'size_equals': {
22 | min = check._zod.def.size
23 | max = check._zod.def.size
24 | break
25 | }
26 | default: {
27 | const _:
28 | | 'bigint_format'
29 | | 'greater_than'
30 | | 'length_equals'
31 | | 'less_than'
32 | | 'max_length'
33 | | 'mime_type'
34 | | 'min_length'
35 | | 'multiple_of'
36 | | 'number_format'
37 | | 'overwrite'
38 | | 'property'
39 | | 'string_format'
40 | | never = check._zod.def.check
41 | break
42 | }
43 | }
44 | }
45 |
46 | max = max === Infinity ? min + getFaker().number.int({ min: 0, max: 10 }) : max
47 | if (context.depth > MAX_DEPTH) {
48 | max = min
49 | }
50 | return new Set(
51 | getFaker().helpers.multiple(() => rootFake(schema._zod.def.valueType, context), { count: { min, max } }),
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { renameSync } from 'node:fs'
3 | import { dirname, resolve } from 'node:path'
4 | import { fileURLToPath } from 'node:url'
5 | import { defineConfig } from 'vite'
6 | import dts from 'vite-plugin-dts'
7 |
8 | const __dirname = dirname(fileURLToPath(import.meta.url))
9 |
10 | export default defineConfig({
11 | build: {
12 | lib: {
13 | entry: {
14 | '.': resolve(__dirname, 'src/v3/index.ts'),
15 | v3: resolve(__dirname, 'src/v3/index.ts'),
16 | v4: resolve(__dirname, 'src/v4/index.ts'),
17 | },
18 | name: 'ZodSchemaFaker',
19 | fileName: 'zod-schema-faker',
20 | formats: ['es', 'cjs'],
21 | },
22 | rollupOptions: {
23 | external: ['zod/v3', 'zod/v4/core'],
24 | output: [
25 | {
26 | format: 'es',
27 | entryFileNames: '[name]/zod-schema-faker.es.js',
28 | },
29 | {
30 | format: 'cjs',
31 | entryFileNames: '[name]/zod-schema-faker.cjs',
32 | },
33 | ],
34 | },
35 | },
36 | plugins: [
37 | dts({
38 | rollupTypes: true,
39 | afterBuild() {
40 | const map = {
41 | 'dist/..d.ts': 'dist/zod-schema-faker.d.ts',
42 | 'dist/v3.d.ts': 'dist/v3/zod-schema-faker.d.ts',
43 | 'dist/v4.d.ts': 'dist/v4/zod-schema-faker.d.ts',
44 | }
45 | for (const [key, value] of Object.entries(map)) {
46 | renameSync(resolve(__dirname, key), resolve(__dirname, value))
47 | }
48 | },
49 | }),
50 | ],
51 | test: {
52 | coverage: {
53 | include: ['src/**/*'],
54 | thresholds: {
55 | '100': true,
56 | },
57 | },
58 | },
59 | })
60 |
--------------------------------------------------------------------------------
/src/v3/zod-bigint-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { getFaker } from './random'
3 | import { lcm } from './utils'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | export class ZodBigIntFaker extends ZodTypeFaker {
7 | fake(): z.infer {
8 | let min: undefined | bigint = undefined
9 | let max: undefined | bigint = undefined
10 | let multipleOf: bigint = 1n
11 | for (const check of this.schema._def.checks) {
12 | switch (check.kind) {
13 | case 'min': {
14 | const _min = check.value + (check.inclusive ? 0n : 1n)
15 | min = min !== undefined ? (min > _min ? min : _min) : _min
16 | break
17 | }
18 | case 'max': {
19 | const _max = check.value - (check.inclusive ? 0n : 1n)
20 | max = max !== undefined ? (max < _max ? max : _max) : _max
21 | break
22 | }
23 | case 'multipleOf': {
24 | const _multipleOf = check.value < 0n ? -check.value : check.value
25 | multipleOf = lcm(multipleOf, _multipleOf)
26 | break
27 | }
28 | /* v8 ignore next 3 */
29 | default: {
30 | const _: never = check
31 | }
32 | }
33 | }
34 | const largeThanMultipleOf = multipleOf * 1000n
35 | if (min !== undefined && max !== undefined) {
36 | if (min > max) {
37 | throw new RangeError()
38 | }
39 | } else if (min !== undefined) {
40 | max = min + largeThanMultipleOf
41 | } else if (max !== undefined) {
42 | min = max - largeThanMultipleOf
43 | } else {
44 | min = -largeThanMultipleOf
45 | max = largeThanMultipleOf
46 | }
47 | return getFaker().number.bigInt({ min, max, multipleOf })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | jobs:
10 | lint:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v6
15 |
16 | - uses: actions/setup-node@v6
17 | with:
18 | node-version-file: '.nvmrc'
19 |
20 | - run: npm ci
21 |
22 | - run: npx prettier --check .
23 |
24 | test:
25 | runs-on: ubuntu-latest
26 |
27 | steps:
28 | - uses: actions/checkout@v6
29 |
30 | - uses: actions/setup-node@v6
31 | with:
32 | node-version-file: '.nvmrc'
33 |
34 | - run: npm ci
35 |
36 | - run: |
37 | npx vitest run
38 | npm run build
39 | npm run pack
40 | cd e2e/issue-189/v3 && npm ci && npm i ../../../zod-schema-faker.tgz && npm run test && cd -
41 | cd e2e/issue-189/v4 && npm ci && npm i ../../../zod-schema-faker.tgz && npm run test && cd -
42 | cd examples/v3 && npm ci && npm i ../../zod-schema-faker.tgz && npm run build && cd -
43 | cd examples/v4 && npm ci && npm i ../../zod-schema-faker.tgz && npm run build && cd -
44 |
45 | build:
46 | runs-on: ubuntu-latest
47 |
48 | needs:
49 | - lint
50 | - test
51 |
52 | steps:
53 | - uses: actions/checkout@v6
54 |
55 | - uses: actions/setup-node@v6
56 | with:
57 | node-version-file: '.nvmrc'
58 |
59 | - run: npm ci
60 |
61 | - run: npm run build
62 |
63 | - uses: JS-DevTools/npm-publish@v4
64 | id: publish
65 | if: ${{ github.ref == 'refs/heads/main' }}
66 | with:
67 | token: ${{ secrets.NPM_TOKEN }}
68 | package: ./package.json
69 | access: public
70 | dry-run: false
71 | strategy: upgrade
72 |
--------------------------------------------------------------------------------
/tests/v3/zod-readonly-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { fake, install } from '../../src/v3'
5 |
6 | test('freeze', () => {
7 | const schema = z.object({ key: z.string() }).readonly()
8 |
9 | install()
10 | const data = fake(schema)
11 |
12 | expect(() => {
13 | // @ts-expect-error
14 | data.key = ''
15 | }).toThrow()
16 | })
17 |
18 | test('object', () => {
19 | const schema = z.object({ key: z.string() }).readonly()
20 |
21 | install()
22 | const data = fake(schema)
23 |
24 | expectType>(true)
25 | expect(schema.safeParse(data).success).toBe(true)
26 | })
27 |
28 | test('array', () => {
29 | const schema = z.array(z.string()).readonly()
30 |
31 | install()
32 | const data = fake(schema)
33 |
34 | expectType>>(true)
35 | expect(schema.safeParse(data).success).toBe(true)
36 | })
37 |
38 | test('tuple', () => {
39 | const schema = z.tuple([z.string(), z.number()]).readonly()
40 |
41 | install()
42 | const data = fake(schema)
43 |
44 | expectType>(true)
45 | expect(schema.safeParse(data).success).toBe(true)
46 | })
47 |
48 | test('map', () => {
49 | const schema = z.map(z.string(), z.date()).readonly()
50 |
51 | install()
52 | const data = fake(schema)
53 |
54 | expectType>>(true)
55 | expect(schema.safeParse(data).success).toBe(true)
56 | })
57 |
58 | test('set', () => {
59 | const schema = z.set(z.string()).readonly()
60 |
61 | install()
62 | const data = fake(schema)
63 |
64 | expectType>>(true)
65 | expect(schema.safeParse(data).success).toBe(true)
66 | })
67 |
--------------------------------------------------------------------------------
/tests/v3/zod-record-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodRecordFaker } from '../../src/v3/zod-record-faker'
6 |
7 | test('ZodRecordFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodRecordFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodRecordFaker should assert type of key', () => {
13 | install()
14 |
15 | const numericalKeySchema = z.record(z.number(), z.any())
16 | const faker = new ZodRecordFaker(numericalKeySchema)
17 | expect(() => faker.fake()).toThrow()
18 | })
19 |
20 | test('ZodRecordFaker should accepts a ZodRecord schema', () => {
21 | const schema = z.record(z.string(), z.number())
22 | expect(() => new ZodRecordFaker(schema)).not.toThrow()
23 | })
24 |
25 | test('ZodRecordFaker should return a ZodRecordFaker instance', () => {
26 | const schema = z.record(z.string(), z.number())
27 | const faker = new ZodRecordFaker(schema)
28 | expect(faker instanceof ZodRecordFaker).toBe(true)
29 | })
30 |
31 | test('ZodRecordFaker.fake should be a function', () => {
32 | const schema = z.record(z.string(), z.number())
33 | const faker = new ZodRecordFaker(schema)
34 | expect(typeof faker.fake).toBe('function')
35 | })
36 |
37 | test('ZodRecordFaker.fake should return record type', () => {
38 | const schema = z.record(z.string(), z.number())
39 | const faker = new ZodRecordFaker(schema)
40 | expectType, Record>>(true)
41 | })
42 |
43 | test('ZodRecordFaker.fake should return a valid data', () => {
44 | install()
45 |
46 | const schema = z.record(z.string(), z.number())
47 | const faker = new ZodRecordFaker(schema)
48 | const data = faker.fake()
49 | expect(schema.safeParse(data).success).toBe(true)
50 | })
51 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/array.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { MAX_DEPTH } from '../config'
3 | import { Context } from '../context'
4 | import { rootFake as internalFake } from '../fake'
5 | import { getFaker } from '../random'
6 | import { Infer } from '../type'
7 |
8 | export function fakeArray(
9 | schema: T,
10 | context: Context,
11 | rootFake: typeof internalFake,
12 | ): Infer {
13 | let min: undefined | number = undefined
14 | let max: undefined | number = undefined
15 | let length: undefined | number = undefined
16 | for (const check of (schema._zod.def.checks ?? []) as core.$ZodChecks[]) {
17 | switch (check._zod.def.check) {
18 | case 'length_equals': {
19 | if (length !== undefined && length !== check._zod.def.length) {
20 | throw new RangeError()
21 | }
22 | length = check._zod.def.length
23 | break
24 | }
25 | case 'max_length': {
26 | max = Math.min(max ?? Infinity, check._zod.def.maximum)
27 | break
28 | }
29 | case 'min_length': {
30 | min = Math.max(min ?? 0, check._zod.def.minimum)
31 | break
32 | }
33 | default: {
34 | const _:
35 | | 'bigint_format'
36 | | 'greater_than'
37 | | 'less_than'
38 | | 'max_size'
39 | | 'mime_type'
40 | | 'min_size'
41 | | 'multiple_of'
42 | | 'number_format'
43 | | 'overwrite'
44 | | 'property'
45 | | 'size_equals'
46 | | 'string_format'
47 | | never = check._zod.def.check
48 | break
49 | }
50 | }
51 | }
52 |
53 | min = min ?? length ?? 0
54 | max = max ?? length ?? min + 3
55 | if (context.depth > MAX_DEPTH) {
56 | max = min
57 | }
58 | return getFaker().helpers.multiple(() => rootFake(schema._zod.def.element, context), { count: { min, max } })
59 | }
60 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/big-int.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 | import { lcm } from '../utils'
7 |
8 | export function fakeBigInt(
9 | schema: T,
10 | context: Context,
11 | rootFake: typeof internalFake,
12 | ): Infer {
13 | let min = undefined
14 | let max = undefined
15 | let multipleOf = 1n
16 | for (const check of (schema._zod.def.checks ?? []) as core.$ZodChecks[]) {
17 | switch (check._zod.def.check) {
18 | case 'greater_than': {
19 | const value = BigInt(check._zod.def.value as any)
20 | const _min = value + (check._zod.def.inclusive ? 0n : 1n)
21 | min = min !== undefined ? (min > _min ? min : _min) : _min
22 | break
23 | }
24 | case 'less_than': {
25 | const value = BigInt(check._zod.def.value as any)
26 | const _max = value - (check._zod.def.inclusive ? 0n : 1n)
27 | max = max !== undefined ? (max < _max ? max : _max) : _max
28 | break
29 | }
30 | case 'multiple_of': {
31 | const value = BigInt(check._zod.def.value as any)
32 | const _multipleOf = value < 0n ? -value : value
33 | multipleOf = lcm(multipleOf, _multipleOf)
34 | break
35 | }
36 | default: {
37 | const _:
38 | | 'bigint_format'
39 | | 'length_equals'
40 | | 'max_length'
41 | | 'max_size'
42 | | 'mime_type'
43 | | 'min_length'
44 | | 'min_size'
45 | | 'number_format'
46 | | 'overwrite'
47 | | 'property'
48 | | 'size_equals'
49 | | 'string_format'
50 | | never = check._zod.def.check
51 | break
52 | }
53 | }
54 | }
55 | if (min === undefined) {
56 | if (max === undefined) {
57 | min = 0n
58 | } else {
59 | min = max - BigInt(10n)
60 | }
61 | }
62 | return getFaker().number.bigInt({ min, max, multipleOf })
63 | }
64 |
--------------------------------------------------------------------------------
/tests/v3/zod-enum-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodEnumFaker } from '../../src/v3/zod-enum-faker'
6 |
7 | test('ZodEnumFaker should assert parameters', () => {
8 | const schema = void 0 as any
9 | expect(() => new ZodEnumFaker(schema)).toThrow()
10 | })
11 |
12 | test('ZodEnumFaker should accepts a ZodEnum schema', () => {
13 | const schema = z.enum(['foo', 'bar'])
14 | expect(() => new ZodEnumFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodEnumFaker should return a ZodEnumFaker instance', () => {
18 | const schema = z.enum(['foo', 'bar'])
19 | const faker = new ZodEnumFaker(schema)
20 | expect(faker instanceof ZodEnumFaker).toBe(true)
21 | })
22 |
23 | test('ZodEnumFaker.fake should be a function', () => {
24 | const schema = z.enum(['foo', 'bar'])
25 | const faker = new ZodEnumFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodEnumFaker.fake should return the given type', () => {
30 | const schema = z.enum(['foo', 'bar'])
31 | const faker = new ZodEnumFaker(schema)
32 | expectType, 'foo' | 'bar'>>(true)
33 | })
34 |
35 | test('ZodEnumFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.enum(['foo', 'bar'])
39 | const faker = new ZodEnumFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
44 | test('ZodEnumFaker.fake.extract should return a valid data', () => {
45 | install()
46 |
47 | const schema = z.enum(['foo', 'bar']).extract(['foo'])
48 | const faker = new ZodEnumFaker(schema)
49 | const data = faker.fake()
50 | expect(schema.safeParse(data).success).toBe(true)
51 | })
52 |
53 | test('ZodEnumFaker.fake.exclude should return a valid data', () => {
54 | install()
55 |
56 | const schema = z.enum(['foo', 'bar']).exclude(['foo'])
57 | const faker = new ZodEnumFaker(schema)
58 | const data = faker.fake()
59 | expect(schema.safeParse(data).success).toBe(true)
60 | })
61 |
--------------------------------------------------------------------------------
/src/v3/random.ts:
--------------------------------------------------------------------------------
1 | import { Faker, fakerEN, SimpleFaker } from '@faker-js/faker'
2 | import RandExp from 'randexp'
3 |
4 | let _faker: Faker = fakerEN
5 |
6 | /**
7 | * Use given faker instance instead of the default one.
8 | *
9 | * @see https://fakerjs.dev/guide/localization.html for more information.
10 | */
11 | export function setFaker(faker: Faker): void {
12 | _faker = faker
13 | }
14 |
15 | /**
16 | * Get the current faker instance.
17 | *
18 | * @default fakerEN
19 | */
20 | export function getFaker(): Faker {
21 | return _faker
22 | }
23 |
24 | const _simpleFaker = new SimpleFaker()
25 | /**
26 | * Create random strings that match a given regular expression.
27 | */
28 | export const randexp = (pattern: string | RegExp, flags?: string): string => {
29 | const randexp = new RandExp(pattern, flags)
30 | randexp.randInt = (from, to) => _simpleFaker.number.int({ min: from, max: to })
31 | return randexp.gen()
32 | }
33 |
34 | /**
35 | * Sets the seed or generates a new one.
36 | *
37 | * This method is intended to allow for consistent values in tests, so you might want to use hardcoded values as the seed.
38 | */
39 | export const seed = (value?: number): void => {
40 | _faker.seed(value)
41 | _simpleFaker.seed(value)
42 | }
43 |
44 | /**
45 | * This exists for compatibility with the previous version. Will be removed in next major version.
46 | *
47 | * @deprecated Use {@link setFaker} instead.
48 | *
49 | * @todo Remove in next major version.
50 | */
51 | export const installFaker: typeof setFaker = setFaker
52 |
53 | /**
54 | * This exists for compatibility with the previous version. Will be removed in next major version.
55 | *
56 | * @deprecated Use {@link getFaker} instead.
57 | *
58 | * @todo Remove in next major version.
59 | */
60 | export const runFake = any>(
61 | runner: Awaited> extends ReturnType ? Runner : never,
62 | ): ReturnType => {
63 | const result = runner(_faker)
64 | if (result instanceof Promise) {
65 | throw new SyntaxError('InternalError: runFake cannot be used with async functions')
66 | }
67 |
68 | return result
69 | }
70 |
--------------------------------------------------------------------------------
/src/v3/zod-number-faker.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod/v3'
2 | import { getFaker } from './random'
3 | import { lcm } from './utils'
4 | import { ZodTypeFaker } from './zod-type-faker'
5 |
6 | export class ZodNumberFaker extends ZodTypeFaker {
7 | fake(): z.infer {
8 | let min: undefined | number = undefined
9 | let max: undefined | number = undefined
10 | let multipleOf: undefined | number = undefined
11 | let int: boolean = false
12 | let finite: boolean = false
13 | for (const check of this.schema._def.checks) {
14 | switch (check.kind) {
15 | case 'min': {
16 | const _min = check.value + (check.inclusive ? 0 : 0.000000000000001)
17 | min = min !== undefined ? Math.max(min, _min) : _min
18 | break
19 | }
20 | case 'max': {
21 | const _max = check.value - (check.inclusive ? 0 : 0.000000000000001)
22 | max = max !== undefined ? Math.min(max, _max) : _max
23 | break
24 | }
25 | case 'multipleOf': {
26 | const _multipleOf = check.value
27 | multipleOf = multipleOf !== undefined ? lcm(multipleOf, _multipleOf) : _multipleOf
28 | break
29 | }
30 | case 'int':
31 | int = true
32 | break
33 | case 'finite':
34 | finite = true
35 | break
36 | /* v8 ignore next 3 */
37 | default: {
38 | const _: never = check
39 | }
40 | }
41 | }
42 |
43 | if (finite === false && int === false && multipleOf === undefined) {
44 | if (min === undefined && getFaker().datatype.boolean({ probability: 0.2 })) {
45 | return -Infinity
46 | }
47 | if (max === undefined && getFaker().datatype.boolean({ probability: 0.2 })) {
48 | return Infinity
49 | }
50 | }
51 |
52 | min ??= Number.MIN_SAFE_INTEGER
53 | max ??= Number.MAX_SAFE_INTEGER
54 | int = int || (multipleOf !== undefined && multipleOf % 1 === 0)
55 | if (min > max) {
56 | throw new RangeError()
57 | }
58 | const method = int ? 'int' : 'float'
59 | return getFaker().number[method]({ min, max, multipleOf })
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/v3/zod-catch-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodCatchFaker } from '../../src/v3/zod-catch-faker'
6 |
7 | test('ZodCatchFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodCatchFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodCatchFaker should accepts a ZodCatch schema', () => {
13 | const schema = z.number().catch(42)
14 | expect(() => new ZodCatchFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodCatchFaker should return a ZodCatchFaker instance', () => {
18 | const schema = z.number().catch(42)
19 | const faker = new ZodCatchFaker(schema)
20 | expect(faker instanceof ZodCatchFaker).toBe(true)
21 | })
22 |
23 | test('ZodCatchFaker.fake should be a function', () => {
24 | const schema = z.number().catch(42)
25 | const faker = new ZodCatchFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodCatchFaker.fake should return catch type', () => {
30 | const schema = z.number().catch(42)
31 | const faker = new ZodCatchFaker(schema)
32 | expectType, z.infer>>(true)
33 | })
34 |
35 | test('ZodCatchFaker.fake should return a valid data', () => {
36 | install()
37 | const schema = z.number().catch(42)
38 | const faker = new ZodCatchFaker(schema)
39 | const data = faker.fake()
40 | expect(schema.safeParse(data).success).toBe(true)
41 | })
42 |
43 | test('ZodCatchFaker.fake should sometimes return catch value', () => {
44 | install()
45 | const schema = z.number().catch(42)
46 | const faker = new ZodCatchFaker(schema)
47 | while (true) {
48 | const data = faker.fake()
49 | if (data === 42) {
50 | return
51 | }
52 | }
53 | })
54 |
55 | test('ZodCatchFaker.fake should sometimes not return catch value', () => {
56 | install()
57 | const schema = z.number().catch(42)
58 | const faker = new ZodCatchFaker(schema)
59 | while (true) {
60 | const data = faker.fake()
61 | if (data !== 42) {
62 | return
63 | }
64 | }
65 | })
66 |
--------------------------------------------------------------------------------
/tests/v3/zod-function-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodFunctionFaker } from '../../src/v3/zod-function-faker'
6 |
7 | test('ZodFunctionFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodFunctionFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodFunctionFaker should accepts a ZodFunction schema', () => {
13 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
14 | expect(() => new ZodFunctionFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodFunctionFaker should return a ZodFunctionFaker instance', () => {
18 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
19 | const faker = new ZodFunctionFaker(schema)
20 | expect(faker instanceof ZodFunctionFaker).toBe(true)
21 | })
22 |
23 | test('ZodFunctionFaker.fake should be a function', () => {
24 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
25 | const faker = new ZodFunctionFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodFunctionFaker.fake should return function type', () => {
30 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
31 | const faker = new ZodFunctionFaker(schema)
32 | expectType, (_: number, __: string) => boolean>>(true)
33 | })
34 |
35 | test('ZodFunctionFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
39 | const faker = new ZodFunctionFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
44 | test('ZodFunctionFaker.fake when the returned function is called, it should return a valid data', () => {
45 | install()
46 |
47 | const schema = z.function(z.tuple([z.number(), z.string()]), z.boolean())
48 | const faker = new ZodFunctionFaker(schema)
49 | const fn = faker.fake()
50 | expect(schema.safeParse(fn).success).toBe(true)
51 | expect(z.boolean().safeParse(fn(1, '')).success).toBe(true)
52 | })
53 |
--------------------------------------------------------------------------------
/tests/v3/zod-lazy-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodLazyFaker } from '../../src/v3/zod-lazy-faker'
6 | import { testMultipleTimes } from './util'
7 |
8 | interface Category {
9 | name: string
10 | subcategories: Category[]
11 | }
12 |
13 | test('ZodLazyFaker should assert parameters', () => {
14 | const invalidSchema = void 0 as any
15 | expect(() => new ZodLazyFaker(invalidSchema)).toThrow()
16 | })
17 |
18 | test('ZodLazyFaker should accepts a ZodLazy schema', () => {
19 | const schema = z.lazy(() =>
20 | z.object({
21 | name: z.string(),
22 | subcategories: z.array(schema),
23 | }),
24 | ) as z.ZodType
25 | expect(() => new ZodLazyFaker(schema)).not.toThrow()
26 | })
27 |
28 | test('ZodLazyFaker should return a ZodLazyFaker instance', () => {
29 | const schema = z.lazy(() =>
30 | z.object({
31 | name: z.string(),
32 | subcategories: z.array(schema),
33 | }),
34 | ) as z.ZodType
35 | const faker = new ZodLazyFaker(schema)
36 | expect(faker instanceof ZodLazyFaker).toBe(true)
37 | })
38 |
39 | test('ZodLazyFaker.fake should be a function', () => {
40 | const schema = z.lazy(() =>
41 | z.object({
42 | name: z.string(),
43 | subcategories: z.array(schema),
44 | }),
45 | ) as z.ZodType
46 | const faker = new ZodLazyFaker(schema)
47 | expect(typeof faker.fake).toBe('function')
48 | })
49 |
50 | test('ZodLazyFaker.fake should return the given type', () => {
51 | const schema = z.lazy(() =>
52 | z.object({
53 | name: z.string(),
54 | subcategories: z.array(schema),
55 | }),
56 | ) as z.ZodType
57 | const faker = new ZodLazyFaker(schema)
58 | expectType, Category>>(true)
59 | })
60 |
61 | testMultipleTimes('ZodLazyFaker.fake should return a valid data', () => {
62 | install()
63 |
64 | const schema = z.lazy(() =>
65 | z.object({
66 | name: z.string(),
67 | subcategories: z.array(schema),
68 | }),
69 | ) as z.ZodType
70 | const faker = new ZodLazyFaker(schema)
71 | const data = faker.fake()
72 | expect(schema.safeParse(data).success).toBe(true)
73 | })
74 |
--------------------------------------------------------------------------------
/tests/v3/zod-default-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodDefaultFaker } from '../../src/v3/zod-default-faker'
6 |
7 | const defaultData = { foo: 'bar' }
8 |
9 | test('ZodDefaultFaker should assert parameters', () => {
10 | const invalidSchema = void 0 as any
11 | expect(() => new ZodDefaultFaker(invalidSchema)).toThrow()
12 | })
13 |
14 | test('ZodDefaultFaker should accepts a ZodDefault schema', () => {
15 | const schema = z.object({}).default(defaultData)
16 | expect(() => new ZodDefaultFaker(schema)).not.toThrow()
17 | })
18 |
19 | test('ZodDefaultFaker should return a ZodDefaultFaker instance', () => {
20 | const schema = z.object({}).default(defaultData)
21 | const faker = new ZodDefaultFaker(schema)
22 | expect(faker instanceof ZodDefaultFaker).toBe(true)
23 | })
24 |
25 | test('ZodDefaultFaker.fake should be a function', () => {
26 | const schema = z.object({}).default(defaultData)
27 | const faker = new ZodDefaultFaker(schema)
28 | expect(typeof faker.fake).toBe('function')
29 | })
30 |
31 | test('ZodDefaultFaker.fake should return object type', () => {
32 | const schema = z.object({}).default(defaultData)
33 | const faker = new ZodDefaultFaker(schema)
34 | expectType, {}>>(true)
35 | })
36 |
37 | test('ZodDefaultFaker.fake should sometimes return defaultData', () => {
38 | install()
39 |
40 | const schema = z.object({}).default(defaultData)
41 | const faker = new ZodDefaultFaker(schema)
42 |
43 | let i = 0
44 | while (++i < 1e3) {
45 | const data = faker.fake()
46 | expect(schema.safeParse(data).success).toBe(true)
47 | if (data === defaultData) {
48 | return
49 | }
50 | }
51 |
52 | throw Error('should not reach here')
53 | })
54 |
55 | test('ZodDefaultFaker.fake should sometimes return non-defaultData', () => {
56 | install()
57 |
58 | const schema = z.object({}).default(defaultData)
59 | const faker = new ZodDefaultFaker(schema)
60 |
61 | let i = 0
62 | while (++i < 1e3) {
63 | const data = faker.fake()
64 | expect(schema.safeParse(data).success).toBe(true)
65 | if (data !== defaultData) {
66 | return
67 | }
68 | }
69 |
70 | throw Error('should not reach here')
71 | })
72 |
--------------------------------------------------------------------------------
/e2e/issue-189/v3/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "issue-189",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "name": "issue-189",
8 | "dependencies": {
9 | "zod": "3.25.76"
10 | },
11 | "devDependencies": {
12 | "@types/node": "24.10.4",
13 | "ts-expect": "1.3.0",
14 | "typescript": "5.9.3"
15 | }
16 | },
17 | "node_modules/@types/node": {
18 | "version": "24.10.4",
19 | "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz",
20 | "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==",
21 | "dev": true,
22 | "license": "MIT",
23 | "dependencies": {
24 | "undici-types": "~7.16.0"
25 | }
26 | },
27 | "node_modules/ts-expect": {
28 | "version": "1.3.0",
29 | "resolved": "https://registry.npmjs.org/ts-expect/-/ts-expect-1.3.0.tgz",
30 | "integrity": "sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==",
31 | "dev": true
32 | },
33 | "node_modules/typescript": {
34 | "version": "5.9.3",
35 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
36 | "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
37 | "dev": true,
38 | "license": "Apache-2.0",
39 | "bin": {
40 | "tsc": "bin/tsc",
41 | "tsserver": "bin/tsserver"
42 | },
43 | "engines": {
44 | "node": ">=14.17"
45 | }
46 | },
47 | "node_modules/undici-types": {
48 | "version": "7.16.0",
49 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
50 | "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
51 | "dev": true,
52 | "license": "MIT"
53 | },
54 | "node_modules/zod": {
55 | "version": "3.25.76",
56 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
57 | "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
58 | "license": "MIT",
59 | "funding": {
60 | "url": "https://github.com/sponsors/colinhacks"
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zod-schema-faker",
3 | "version": "2.0.2",
4 | "description": "Generates mock data from zod schema. Powered by @faker-js/faker and randexp.js",
5 | "keywords": [
6 | "zod",
7 | "faker-js",
8 | "fake",
9 | "stub",
10 | "mock",
11 | "test",
12 | "json",
13 | "schema"
14 | ],
15 | "homepage": "https://github.com/soc221b/zod-schema-faker#readme",
16 | "bugs": {
17 | "url": "https://github.com/soc221b/zod-schema-faker/issues"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/soc221b/zod-schema-faker.git"
22 | },
23 | "license": "MIT",
24 | "author": "Ernest ",
25 | "sideEffects": false,
26 | "type": "module",
27 | "exports": {
28 | ".": {
29 | "types": "./dist/zod-schema-faker.d.ts",
30 | "import": "./dist/zod-schema-faker.es.js",
31 | "require": "./dist/zod-schema-faker.cjs"
32 | },
33 | "./v3": {
34 | "types": "./dist/v3/zod-schema-faker.d.ts",
35 | "import": "./dist/v3/zod-schema-faker.es.js",
36 | "require": "./dist/v3/zod-schema-faker.cjs"
37 | },
38 | "./v4": {
39 | "types": "./dist/v4/zod-schema-faker.d.ts",
40 | "import": "./dist/v4/zod-schema-faker.es.js",
41 | "require": "./dist/v4/zod-schema-faker.cjs"
42 | }
43 | },
44 | "main": "./dist/zod-schema-faker.cjs",
45 | "module": "./dist/zod-schema-faker.es.js",
46 | "types": "./dist/zod-schema-faker.d.ts",
47 | "files": [
48 | "dist"
49 | ],
50 | "scripts": {
51 | "build": "tsc && vite build",
52 | "format": "prettier --write .",
53 | "pack": "rm -f *.tgz && npm pack && mv zod-schema-faker* zod-schema-faker.tgz",
54 | "test": "vitest"
55 | },
56 | "dependencies": {
57 | "@faker-js/faker": "10.1.0",
58 | "randexp": "0.5.3"
59 | },
60 | "devDependencies": {
61 | "@types/node": "24.10.4",
62 | "@vitest/coverage-v8": "4.0.16",
63 | "prettier": "3.7.4",
64 | "prettier-plugin-organize-imports": "4.3.0",
65 | "prettier-plugin-packagejson": "2.5.20",
66 | "prettier-plugin-sort-json": "4.1.1",
67 | "rimraf": "6.1.2",
68 | "ts-expect": "1.3.0",
69 | "ts-node": "10.9.2",
70 | "typescript": "5.9.3",
71 | "vite": "7.3.0",
72 | "vite-plugin-dts": "4.5.4",
73 | "vitest": "4.0.16",
74 | "zod": "4.1.12"
75 | },
76 | "peerDependencies": {
77 | "zod": "^3.25.0 || ^4.0.0"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tests/v3/zod-tuple-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { describe, expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodTupleFaker } from '../../src/v3/zod-tuple-faker'
6 |
7 | test('ZodTupleFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodTupleFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodTupleFaker should accepts a ZodTuple schema', () => {
13 | const schema = z.tuple([z.number(), z.string()]).rest(z.boolean())
14 | expect(() => new ZodTupleFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodTupleFaker should return a ZodTupleFaker instance', () => {
18 | const schema = z.tuple([z.number(), z.string()]).rest(z.boolean())
19 | const faker = new ZodTupleFaker(schema)
20 | expect(faker instanceof ZodTupleFaker).toBe(true)
21 | })
22 |
23 | test('ZodTupleFaker.fake should be a function', () => {
24 | const schema = z.tuple([z.number(), z.string()]).rest(z.boolean())
25 | const faker = new ZodTupleFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | describe('without rest', () => {
30 | test('ZodTupleFaker.fake should return tuple type', () => {
31 | const schema = z.tuple([z.number(), z.string()])
32 | const faker = new ZodTupleFaker(schema)
33 | expectType['0'], number>>(true)
34 | expectType['1'], string>>(true)
35 | })
36 |
37 | test('ZodTupleFaker.fake should return a valid data', () => {
38 | install()
39 |
40 | const schema = z.tuple([z.number(), z.string()])
41 | const faker = new ZodTupleFaker(schema)
42 | const data = faker.fake()
43 | expect(schema.safeParse(data).success).toBe(true)
44 | })
45 | })
46 |
47 | describe('rest', () => {
48 | test('ZodTupleFaker.fake should return tuple type', () => {
49 | const schema = z.tuple([z.number(), z.string()]).rest(z.boolean())
50 | const faker = new ZodTupleFaker(schema)
51 | expectType, [number, string, ...boolean[]]>>(true)
52 | })
53 |
54 | test('ZodTupleFaker.fake should return a valid data', () => {
55 | install()
56 |
57 | const schema = z.tuple([z.number(), z.string()]).rest(z.boolean())
58 | const faker = new ZodTupleFaker(schema)
59 | const data = faker.fake()
60 | expect(schema.safeParse(data).success).toBe(true)
61 | })
62 | })
63 |
--------------------------------------------------------------------------------
/tests/v3/zod-discriminated-union-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodDiscriminatedUnionFaker } from '../../src/v3/zod-discriminated-union-faker'
6 |
7 | test('ZodDiscriminatedUnionFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodDiscriminatedUnionFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodDiscriminatedUnionFaker should accepts a ZodDiscriminatedUnion schema', () => {
13 | const schema = z.discriminatedUnion('type', [
14 | z.object({ type: z.literal('a'), a: z.string() }),
15 | z.object({ type: z.literal('b'), b: z.string() }),
16 | ])
17 | expect(() => new ZodDiscriminatedUnionFaker(schema)).not.toThrow()
18 | })
19 |
20 | test('ZodDiscriminatedUnionFaker should return a ZodDiscriminatedUnionFaker instance', () => {
21 | const schema = z.discriminatedUnion('type', [
22 | z.object({ type: z.literal('a'), a: z.string() }),
23 | z.object({ type: z.literal('b'), b: z.string() }),
24 | ])
25 | const faker = new ZodDiscriminatedUnionFaker(schema)
26 | expect(faker instanceof ZodDiscriminatedUnionFaker).toBe(true)
27 | })
28 |
29 | test('ZodDiscriminatedUnionFaker.fake should be a function', () => {
30 | const schema = z.discriminatedUnion('type', [
31 | z.object({ type: z.literal('a'), a: z.string() }),
32 | z.object({ type: z.literal('b'), b: z.string() }),
33 | ])
34 | const faker = new ZodDiscriminatedUnionFaker(schema)
35 | expect(typeof faker.fake).toBe('function')
36 | })
37 |
38 | test('ZodDiscriminatedUnionFaker.fake should return the given type', () => {
39 | const schema = z.discriminatedUnion('type', [
40 | z.object({ type: z.literal('a'), a: z.string() }),
41 | z.object({ type: z.literal('b'), b: z.string() }),
42 | ])
43 | const faker = new ZodDiscriminatedUnionFaker(schema)
44 | expectType, { type: 'a'; a: string } | { type: 'b'; b: string }>>(true)
45 | })
46 |
47 | test('ZodDiscriminatedUnionFaker.fake should return a valid data', () => {
48 | install()
49 |
50 | const schema = z.discriminatedUnion('type', [
51 | z.object({ type: z.literal('a'), a: z.string() }),
52 | z.object({ type: z.literal('b'), b: z.string() }),
53 | ])
54 | const faker = new ZodDiscriminatedUnionFaker(schema)
55 | const data = faker.fake()
56 | expect(schema.safeParse(data).success).toBe(true)
57 | })
58 |
--------------------------------------------------------------------------------
/tests/v4/random.test.ts:
--------------------------------------------------------------------------------
1 | import { Faker } from '@faker-js/faker'
2 | import { describe, expect, it } from 'vitest'
3 | import * as z from 'zod'
4 | import { fake } from '../../src/v4'
5 | import { getFaker, randexp, seed, setFaker } from '../../src/v4/internals/random'
6 |
7 | describe('@faker-js/faker', () => {
8 | it('does not have a default faker', () => {
9 | expect(() => getFaker()).toThrow()
10 | })
11 |
12 | it('can set a faker', () => {
13 | const faker = new Faker({ locale: {} })
14 |
15 | setFaker(faker)
16 |
17 | expect(getFaker()).toEqual(faker)
18 | })
19 | })
20 |
21 | describe('randexp', () => {
22 | it('should works', () => {
23 | const regex = /^foo|bar$/
24 | const data = randexp(regex)
25 | expect(data).toBeTypeOf('string')
26 | expect(data).toMatch(regex)
27 | })
28 | })
29 |
30 | describe('seed', () => {
31 | it('should set seed for getFaker', () => {
32 | const gen = () => getFaker().number.int()
33 |
34 | seed(97)
35 | const data1 = gen()
36 | expect(data1).toMatchInlineSnapshot(`7538522492335270`)
37 |
38 | seed(97)
39 | const data2 = gen()
40 | expect(data1).toBe(data2)
41 |
42 | const data3 = gen()
43 | expect(data1).not.toBe(data3)
44 | })
45 |
46 | it('should set seed for randexp', () => {
47 | const gen = () => randexp(/\d{50}/)
48 |
49 | seed(61)
50 | const data1 = gen()
51 | expect(data1).toMatchInlineSnapshot(`"81849096331484486007704357152196940134457972127416"`)
52 |
53 | seed(61)
54 | const data2 = gen()
55 | expect(data1).toBe(data2)
56 |
57 | const data3 = gen()
58 | expect(data1).not.toBe(data3)
59 | })
60 |
61 | it.skip('should works together', () => {
62 | const schema = z.object({
63 | foo: z.number(),
64 | bar: z.number(),
65 | date: z.date(),
66 | string: z.object({
67 | date: z.string().date(),
68 | datetime: z.string().datetime(),
69 | time: z.string().time(),
70 | }),
71 | })
72 | const gen = () => fake(schema)
73 |
74 | seed(3)
75 | const data1 = gen()
76 | expect(data1).toMatchInlineSnapshot(`
77 | {
78 | "bar": 7138981630600537,
79 | "date": -271821-05-08T18:51:09.723Z,
80 | "foo": -3766725359666402,
81 | "string": {
82 | "date": "4408-02-05",
83 | "datetime": "0298-10-05T14:52:06.368Z",
84 | "time": "02:09:02",
85 | },
86 | }
87 | `)
88 |
89 | seed(3)
90 | const data2 = gen()
91 | expect(data1).toEqual(data2)
92 |
93 | const data3 = gen()
94 | expect(data1).not.toEqual(data3)
95 | })
96 | })
97 |
--------------------------------------------------------------------------------
/tests/v3/zod-set-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { describe, expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodSetFaker } from '../../src/v3/zod-set-faker'
6 |
7 | test('ZodSetFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodSetFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodSetFaker should accepts a ZodSet schema', () => {
13 | const schema = z.set(z.number())
14 | expect(() => new ZodSetFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodSetFaker should return a ZodSetFaker instance', () => {
18 | const schema = z.set(z.number())
19 | const faker = new ZodSetFaker(schema)
20 | expect(faker instanceof ZodSetFaker).toBe(true)
21 | })
22 |
23 | test('ZodSetFaker.fake should be a function', () => {
24 | const schema = z.set(z.number())
25 | const faker = new ZodSetFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodSetFaker.fake should return set type', () => {
30 | const schema = z.set(z.number())
31 | const faker = new ZodSetFaker(schema)
32 | expectType, Set>>(true)
33 | })
34 |
35 | test('ZodSetFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.set(z.number())
39 | const faker = new ZodSetFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
44 | test('non-empty', () => {
45 | install()
46 |
47 | const schema = z.set(z.number()).nonempty()
48 | const faker = new ZodSetFaker(schema)
49 | const data = faker.fake()
50 | expect(schema.safeParse(data).success).toBe(true)
51 | })
52 |
53 | test('min', () => {
54 | install()
55 |
56 | const schema = z.set(z.number()).min(5)
57 | const faker = new ZodSetFaker(schema)
58 | const data = faker.fake()
59 | expect(schema.safeParse(data).success).toBe(true)
60 | })
61 |
62 | test('max', () => {
63 | install()
64 |
65 | const schema = z.set(z.number()).max(5)
66 | const faker = new ZodSetFaker(schema)
67 | const data = faker.fake()
68 | expect(schema.safeParse(data).success).toBe(true)
69 | })
70 |
71 | test('size', () => {
72 | install()
73 |
74 | const schema = z.set(z.number()).size(5)
75 | const faker = new ZodSetFaker(schema)
76 | const data = faker.fake()
77 | expect(schema.safeParse(data).success).toBe(true)
78 | })
79 |
80 | describe('impossible case', () => {
81 | test('min > max', () => {
82 | install()
83 |
84 | const schema = z.set(z.number()).min(10).max(5)
85 | const faker = new ZodSetFaker(schema)
86 | expect(() => faker.fake()).toThrow(RangeError)
87 | })
88 | })
89 |
--------------------------------------------------------------------------------
/tests/v3/zod-native-enum-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodNativeEnumFaker } from '../../src/v3/zod-native-enum-faker'
6 |
7 | enum NativeEnum {
8 | Foo,
9 | Bar,
10 | Baz = 'baz',
11 | Qux = 'qux',
12 | }
13 |
14 | test('ZodNativeEnumFaker should assert parameters', () => {
15 | const invalidSchema = void 0 as any
16 | expect(() => new ZodNativeEnumFaker(invalidSchema)).toThrow()
17 | })
18 |
19 | test('ZodNativeEnumFaker should accepts a ZodNativeEnum schema', () => {
20 | const schema = z.nativeEnum(NativeEnum)
21 | expect(() => new ZodNativeEnumFaker(schema)).not.toThrow()
22 | })
23 |
24 | test('ZodNativeEnumFaker should return a ZodNativeEnumFaker instance', () => {
25 | const schema = z.nativeEnum(NativeEnum)
26 | const faker = new ZodNativeEnumFaker(schema)
27 | expect(faker instanceof ZodNativeEnumFaker).toBe(true)
28 | })
29 |
30 | test('ZodNativeEnumFaker.fake should be a function', () => {
31 | const schema = z.nativeEnum(NativeEnum)
32 | const faker = new ZodNativeEnumFaker(schema)
33 | expect(typeof faker.fake).toBe('function')
34 | })
35 |
36 | test('ZodNativeEnumFaker.fake should return the give type', () => {
37 | const schema = z.nativeEnum(NativeEnum)
38 | const faker = new ZodNativeEnumFaker(schema)
39 | expectType, NativeEnum>>(false)
40 | })
41 |
42 | test('ZodNativeEnumFaker.fake should return a valid data', () => {
43 | install()
44 |
45 | const schema = z.nativeEnum(NativeEnum)
46 | const faker = new ZodNativeEnumFaker(schema)
47 | const data = faker.fake()
48 | expect(schema.safeParse(data).success).toBe(true)
49 | })
50 |
51 | test('numeric enums', () => {
52 | enum Fruits {
53 | Apple,
54 | Banana,
55 | }
56 | const schema = z.nativeEnum(Fruits)
57 | const faker = new ZodNativeEnumFaker(schema)
58 | const data = faker.fake()
59 | expect(schema.safeParse(data).success).toBe(true)
60 | })
61 |
62 | test('string enums', () => {
63 | enum Fruits {
64 | Cantaloupe, // you can mix numerical and string enums
65 | Apple = 'apple',
66 | Banana = 'banana',
67 | }
68 | const schema = z.nativeEnum(Fruits)
69 | const faker = new ZodNativeEnumFaker(schema)
70 | const data = faker.fake()
71 | expect(schema.safeParse(data).success).toBe(true)
72 | })
73 |
74 | test('const enums', () => {
75 | const Fruits = {
76 | Apple: 'apple',
77 | Banana: 'banana',
78 | Cantaloupe: 3,
79 | } as const
80 |
81 | const schema = z.nativeEnum(Fruits)
82 | const faker = new ZodNativeEnumFaker(schema)
83 | const data = faker.fake()
84 | expect(schema.safeParse(data).success).toBe(true)
85 | })
86 |
--------------------------------------------------------------------------------
/tests/v3/zod-effects-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { expect, test, vi } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodEffectsFaker } from '../../src/v3/zod-effects-faker'
6 |
7 | test('type', () => {
8 | install()
9 | const data = new ZodEffectsFaker(z.preprocess(val => String(val), z.string().min(5).max(10))).fake()
10 | expectType>(true)
11 | })
12 |
13 | test('ZodEffectsFaker should return a ZodEffectsFaker instance', () => {
14 | const schema = z.preprocess(val => String(val), z.string().min(5).max(10))
15 | const faker = new ZodEffectsFaker(schema)
16 | expect(faker instanceof ZodEffectsFaker).toBe(true)
17 | })
18 |
19 | test('it should not throw error when schema has preprocess-effects', () => {
20 | install()
21 | const schema = z.string().min(5).max(10)
22 | const preprocess = z.preprocess(val => String(val), schema)
23 | const faker = new ZodEffectsFaker(preprocess)
24 |
25 | expect(() => faker.fake()).not.toThrow()
26 |
27 | const data = faker.fake()
28 |
29 | expect(schema.safeParse(data).success).toBe(true)
30 | })
31 |
32 | test('it should ignore preprocess-effects', () => {
33 | install()
34 | const fn = vi.fn()
35 | const schema = z.string().min(5).max(10)
36 | const preprocess = z.preprocess(fn, schema)
37 | const faker = new ZodEffectsFaker(preprocess)
38 |
39 | faker.fake()
40 |
41 | expect(fn).not.toHaveBeenCalled()
42 | })
43 |
44 | test('it should not throw error when schema has refine-effects', () => {
45 | install()
46 | const schema = z.string().refine(val => val.length <= 255, {
47 | message: "String can't be more than 255 characters",
48 | })
49 | const faker = new ZodEffectsFaker(schema)
50 |
51 | const act = () => faker.fake()
52 |
53 | expect(act).not.toThrow()
54 | })
55 |
56 | test('it should ignore refine-effects', () => {
57 | install()
58 | const fn = vi.fn()
59 | const schema = z.string().length(300).refine(fn, {
60 | message: "String can't be more than 255 characters",
61 | })
62 | const faker = new ZodEffectsFaker(schema)
63 |
64 | faker.fake()
65 |
66 | expect(fn).not.toHaveBeenCalled()
67 | })
68 |
69 | test('it should not throw error when schema has transform-effects', () => {
70 | install()
71 | const schema = z.string().transform(val => val.length)
72 | const faker = new ZodEffectsFaker(schema)
73 |
74 | const act = () => faker.fake()
75 |
76 | expect(act).not.toThrow()
77 | })
78 |
79 | test('it should execute transform-effects', () => {
80 | install()
81 | const schema = z.string().transform(val => val.length)
82 | const faker = new ZodEffectsFaker(schema)
83 |
84 | const data = faker.fake()
85 |
86 | expectType>(true)
87 | expect(typeof data).toBe('number')
88 | })
89 |
--------------------------------------------------------------------------------
/tests/v3/zod-promise-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { afterEach, beforeEach, expect, test, vitest } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodPromiseFaker } from '../../src/v3/zod-promise-faker'
6 |
7 | beforeEach(() => {
8 | vitest.useFakeTimers()
9 | })
10 |
11 | afterEach(() => {
12 | vitest.useRealTimers()
13 | })
14 |
15 | test('ZodPromiseFaker should assert parameters', () => {
16 | const invalidSchema = void 0 as any
17 | expect(() => new ZodPromiseFaker(invalidSchema)).toThrow()
18 | })
19 |
20 | test('ZodPromiseFaker should accepts a ZodPromise schema', () => {
21 | const schema = z.promise(z.string())
22 | expect(() => new ZodPromiseFaker(schema)).not.toThrow()
23 | })
24 |
25 | test('ZodPromiseFaker should return a ZodPromiseFaker instance', () => {
26 | const schema = z.promise(z.string())
27 | const faker = new ZodPromiseFaker(schema)
28 | expect(faker instanceof ZodPromiseFaker).toBe(true)
29 | })
30 |
31 | test('ZodPromiseFaker.fake should be a function', () => {
32 | const schema = z.promise(z.string())
33 | const faker = new ZodPromiseFaker(schema)
34 | expect(typeof faker.fake).toBe('function')
35 | })
36 |
37 | test('ZodPromiseFaker.fake should return promise type', () => {
38 | const schema = z.promise(z.string())
39 | const faker = new ZodPromiseFaker(schema)
40 | expectType, Promise>>(true)
41 | })
42 |
43 | test('ZodPromiseFaker.fake should return a valid data', async () => {
44 | install()
45 |
46 | const schema = z.promise(z.string())
47 | const faker = new ZodPromiseFaker(schema)
48 | const data = faker.fake()
49 | vitest.runAllTimers()
50 | expect((await schema.safeParseAsync(data)).success).toBe(true)
51 | })
52 |
53 | test('microtask', async () => {
54 | install()
55 | const schema = z.promise(z.string())
56 | const faker = new ZodPromiseFaker(schema)
57 |
58 | while (true) {
59 | let data
60 | faker.fake().then(_data => {
61 | data = _data
62 | })
63 | const micro = Promise.resolve()
64 | vitest.runAllTicks()
65 | await micro
66 | if (typeof data === 'string') {
67 | return
68 | }
69 | }
70 | })
71 |
72 | test('task', async () => {
73 | install()
74 | const schema = z.promise(z.string())
75 | const faker = new ZodPromiseFaker(schema)
76 |
77 | while (true) {
78 | let data
79 | faker.fake().then(_data => {
80 | data = _data
81 | })
82 | const micro = Promise.resolve()
83 | const macro = new Promise(resolve => setTimeout(resolve))
84 | vitest.runAllTicks()
85 | await micro
86 | if (typeof data === 'string') {
87 | continue
88 | }
89 | await vitest.advanceTimersByTime(0)
90 | await macro
91 | if (typeof data === 'string') {
92 | return
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/tests/v3/integration.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeEach, expect } from 'vitest'
2 | import { z } from 'zod/v3'
3 | import { fake, install } from '../../src/v3'
4 | import { testMultipleTimes } from './util'
5 |
6 | beforeEach(() => {
7 | install()
8 | })
9 |
10 | testMultipleTimes('integration', async () => {
11 | interface Category {
12 | name: string
13 | subcategories: Category[]
14 | }
15 | const category = z.lazy(() =>
16 | z.object({
17 | name: z.string(),
18 | subcategories: z.array(category),
19 | }),
20 | ) as z.ZodType
21 |
22 | const schema = z.object({
23 | primitives: z.object({
24 | string: z.string(),
25 | number: z.number(),
26 | bigint: z.bigint(),
27 | boolean: z.boolean(),
28 | date: z.date(),
29 | }),
30 | emptyValues: z.object({
31 | undefined: z.undefined(),
32 | null: z.null(),
33 | void: z.void(),
34 | }),
35 | any: z.any(),
36 | unknown: z.unknown(),
37 | // never: z.never(), // always throws an error
38 | literal: z.literal('tuna'),
39 | strings: z.object({
40 | max: z.string().max(5),
41 | min: z.string().min(5),
42 | length: z.string().length(5),
43 | email: z.string().email(),
44 | url: z.string().url(),
45 | uuid: z.string().uuid(),
46 | cuid: z.string().cuid(),
47 | regex: z.string().regex(/hello+ (world|to you)/),
48 | }),
49 | numbers: z.object({
50 | gt: z.number().gt(5),
51 | gte: z.number().gte(5),
52 | lt: z.number().lt(5),
53 | lte: z.number().lte(5),
54 | int: z.number().int(),
55 | positive: z.number().positive(),
56 | nonnegative: z.number().nonnegative(),
57 | negative: z.number().negative(),
58 | nonpositive: z.number().nonpositive(),
59 | multipleOf: z.number().multipleOf(31),
60 | }),
61 | nan: z.nan(),
62 | boolean: z.boolean(),
63 | date: z.date(),
64 | enum: z.enum(['Salmon', 'Tuna', 'Trout']),
65 | nativeEnum: z.nativeEnum({
66 | Apple: 'apple',
67 | Banana: 'banana',
68 | Cantaloupe: 3,
69 | } as const),
70 | optional: z.optional(z.string()),
71 | nullable: z.nullable(z.string()),
72 | object: z.object({
73 | name: z.string(),
74 | age: z.number(),
75 | }),
76 | array: z.array(z.string()),
77 | tuple: z.tuple([
78 | z.string(),
79 | z.number(),
80 | z.object({
81 | pointsScored: z.number(),
82 | }),
83 | ]),
84 | union: z.union([z.string(), z.number()]),
85 | discriminatedUnions: z.discriminatedUnion('type', [
86 | z.object({ type: z.literal('a'), a: z.string() }),
87 | z.object({ type: z.literal('b'), b: z.string() }),
88 | ]),
89 | record: z.record(z.string(), z.number()),
90 | map: z.map(z.string(), z.number()),
91 | set: z.set(z.number()),
92 | lazy: category,
93 | promise: z.promise(z.number()),
94 | })
95 |
96 | const data = fake(schema)
97 |
98 | expect(schema.safeParse(data).success).toBe(true)
99 |
100 | await data.promise
101 | })
102 |
--------------------------------------------------------------------------------
/tests/v3/random.test.ts:
--------------------------------------------------------------------------------
1 | import { fakerAR, fakerEN, fakerJA } from '@faker-js/faker'
2 | import { describe, expect, test, vi } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { fake, getFaker, install, installFaker, randexp, runFake, seed, setFaker } from '../../src/v3'
5 |
6 | describe('@faker-js/faker', () => {
7 | test('default', () => {
8 | const spy = vi.spyOn(fakerEN.lorem, 'word')
9 |
10 | const data = getFaker().lorem.word()
11 | expect(data).toBeTypeOf('string')
12 | expect(spy).toHaveBeenCalled()
13 |
14 | spy.mockReset()
15 |
16 | const data2 = runFake(faker => faker.lorem.word())
17 | expect(data2).toBeTypeOf('string')
18 | expect(spy).toHaveBeenCalled()
19 | })
20 |
21 | test('custom', () => {
22 | const spyJA = vi.spyOn(fakerJA.lorem, 'word')
23 | setFaker(fakerJA)
24 | const data = getFaker().lorem.word()
25 | expect(data).toBeTypeOf('string')
26 | expect(spyJA).toHaveBeenCalled()
27 |
28 | const spyAR = vi.spyOn(fakerAR.lorem, 'word')
29 | installFaker(fakerAR)
30 | const data2 = runFake(faker => faker.lorem.word())
31 | expect(data2).toBeTypeOf('string')
32 | expect(spyAR).toHaveBeenCalled()
33 | })
34 |
35 | test('runFake can not be used with async functions', () => {
36 | // @ts-expect-error
37 | expect(() => runFake(async () => {})).toThrow()
38 | })
39 | })
40 |
41 | describe('randexp', () => {
42 | test('randexp', () => {
43 | const regex = /^foo|bar$/
44 | const data = randexp(regex)
45 | expect(data).toBeTypeOf('string')
46 | expect(data).toMatch(regex)
47 | })
48 | })
49 |
50 | describe('seed', () => {
51 | test('getFaker', () => {
52 | const gen = () => getFaker().number.int()
53 |
54 | seed(97)
55 | const data1 = gen()
56 | expect(data1).toMatchInlineSnapshot(`7538522492335270`)
57 |
58 | seed(97)
59 | const data2 = gen()
60 | expect(data1).toBe(data2)
61 |
62 | const data3 = gen()
63 | expect(data1).not.toBe(data3)
64 | })
65 |
66 | test('randexp', () => {
67 | const gen = () => randexp(/\d{50}/)
68 |
69 | seed(61)
70 | const data1 = gen()
71 | expect(data1).toMatchInlineSnapshot(`"81849096331484486007704357152196940134457972127416"`)
72 |
73 | seed(61)
74 | const data2 = gen()
75 | expect(data1).toBe(data2)
76 |
77 | const data3 = gen()
78 | expect(data1).not.toBe(data3)
79 | })
80 |
81 | test('integration', () => {
82 | install()
83 | const schema = z.object({
84 | foo: z.number(),
85 | bar: z.number(),
86 | date: z.date(),
87 | string: z.object({
88 | date: z.string().date(),
89 | datetime: z.string().datetime(),
90 | time: z.string().time(),
91 | }),
92 | })
93 | const gen = () => fake(schema)
94 |
95 | seed(3)
96 | const data1 = gen()
97 | expect(data1).toMatchInlineSnapshot(`
98 | {
99 | "bar": 7138981630600537,
100 | "date": -271821-05-08T18:51:09.723Z,
101 | "foo": -3766725359666402,
102 | "string": {
103 | "date": "4408-02-05",
104 | "datetime": "0298-10-05T14:52:06.368Z",
105 | "time": "02:09:02",
106 | },
107 | }
108 | `)
109 |
110 | seed(3)
111 | const data2 = gen()
112 | expect(data1).toEqual(data2)
113 |
114 | const data3 = gen()
115 | expect(data1).not.toEqual(data3)
116 | })
117 | })
118 |
--------------------------------------------------------------------------------
/tests/v3/zod-date-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { describe, expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { ZodDateFaker } from '../../src/v3/zod-date-faker'
5 |
6 | test('ZodDateFaker should assert parameters', () => {
7 | const invalidSchema = void 0 as any
8 | expect(() => new ZodDateFaker(invalidSchema)).toThrow()
9 | })
10 |
11 | test('ZodDateFaker should accepts a ZodDate schema', () => {
12 | const schema = z.date()
13 | expect(() => new ZodDateFaker(schema)).not.toThrow()
14 | })
15 |
16 | test('ZodDateFaker should return a ZodDateFaker instance', () => {
17 | const schema = z.date()
18 | const faker = new ZodDateFaker(schema)
19 | expect(faker instanceof ZodDateFaker).toBe(true)
20 | })
21 |
22 | test('ZodDateFaker.fake should be a function', () => {
23 | const schema = z.date()
24 | const faker = new ZodDateFaker(schema)
25 | expect(typeof faker.fake).toBe('function')
26 | })
27 |
28 | test('ZodDateFaker.fake should return date type', () => {
29 | const schema = z.date()
30 | const faker = new ZodDateFaker(schema)
31 | expectType, Date>>(true)
32 | })
33 |
34 | test('ZodDateFaker.fake should return a valid data', () => {
35 | const schema = z.date()
36 | const faker = new ZodDateFaker(schema)
37 | const data = faker.fake()
38 | expect(schema.safeParse(data).success).toBe(true)
39 | })
40 |
41 | test('min', () => {
42 | const schema = z.date().min(new Date('2000-01-01'))
43 | const faker = new ZodDateFaker(schema)
44 | const data = faker.fake()
45 | expect(schema.safeParse(data).success).toBe(true)
46 | })
47 |
48 | test('max', () => {
49 | const schema = z.date().max(new Date('2000-01-01'))
50 | const faker = new ZodDateFaker(schema)
51 | const data = faker.fake()
52 | expect(schema.safeParse(data).success).toBe(true)
53 | })
54 |
55 | test('should sometimes generate an edge date (min)', () => {
56 | const schema = z.date()
57 | const faker = new ZodDateFaker(schema)
58 | while (true) {
59 | const data = faker.fake()
60 | if (data.getTime() < new Date('1970-01-01').getTime()) {
61 | break
62 | }
63 | }
64 | })
65 |
66 | test('should sometimes generate an edge date (max)', () => {
67 | const schema = z.date()
68 | const faker = new ZodDateFaker(schema)
69 | while (true) {
70 | const data = faker.fake()
71 | if (data.getTime() > new Date('2038-01-19').getTime()) {
72 | break
73 | }
74 | }
75 | })
76 |
77 | describe('multiple checks of the same kind', () => {
78 | test('min', () => {
79 | const schema = z
80 | .date()
81 | .min(new Date('2000-01-01T00:00:00.000Z'))
82 | .min(new Date('2002-01-01T00:00:00.000Z'))
83 | .min(new Date('2001-01-01T00:00:00.000Z'))
84 | .max(new Date('2002-01-01T00:00:00.000Z'))
85 | const faker = new ZodDateFaker(schema)
86 | const data = faker.fake()
87 | expect(schema.safeParse(data).data).toEqual(new Date('2002-01-01T00:00:00.000Z'))
88 | })
89 |
90 | test('max', () => {
91 | const schema = z
92 | .date()
93 | .max(new Date('2002-01-01T00:00:00.000Z'))
94 | .max(new Date('2000-01-01T00:00:00.000Z'))
95 | .max(new Date('2001-01-01T00:00:00.000Z'))
96 | .min(new Date('2000-01-01T00:00:00.000Z'))
97 | const faker = new ZodDateFaker(schema)
98 | const data = faker.fake()
99 | expect(schema.safeParse(data).data).toEqual(new Date('2000-01-01T00:00:00.000Z'))
100 | })
101 | })
102 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Open Development
4 |
5 | All work on Zod-schema-faker happens directly on GitHub.
6 |
7 | ## Semantic Versioning
8 |
9 | Zod-schema-faker follows [semantic versioning](https://semver.org/). We release patch versions for critical bugfixes,
10 | minor versions for new features or non-essential changes, and major versions for any breaking changes. When we make
11 | breaking changes, we also introduce deprecation warnings in a minor version so that our users learn about the upcoming
12 | changes and migrate their code in advance.
13 |
14 | Every significant change is documented in the
15 | [changelog file](https://github.com/soc221b/zod-schema-faker/blob/main/CHANGELOG.md).
16 |
17 | ## Branch Organization
18 |
19 | Submit all changes directly to the [main branch](https://github.com/soc221b/zod-schema-faker/tree/main). We don’t use
20 | separate branches for development or for upcoming releases. We do our best to keep `main` in good shape, with all tests
21 | passing.
22 |
23 | Code that lands in `main` must be compatible with the latest stable release. It may contain additional features, but no
24 | breaking changes. We should be able to release a new minor version from the tip of `main` at any time.
25 |
26 | ## Bugs
27 |
28 | ### Where to Find Known Issues
29 |
30 | We are using [GitHub Issues](https://github.com/soc221b/zod-schema-faker/issues) for our public bugs. We keep a close
31 | eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make
32 | sure your problem doesn’t already exist.
33 |
34 | ### Reporting New Issues
35 |
36 | The best way to get your bug fixed is to provide a reduced test case. This
37 | [StackBlitz template](https://stackblitz.com/edit/zod-schema-faker?file=src%2Fmain.ts) is a great starting point.
38 |
39 | ## Proposing a Change
40 |
41 | If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend
42 | [filing an issue](https://github.com/soc221b/zod-schema-faker/issues/new). This lets us reach an agreement on your
43 | proposal before you put significant effort into it.
44 |
45 | If you’re only fixing a bug, it’s fine to submit a pull request right away but we still recommend to file an issue
46 | detailing what you’re fixing. This is helpful in case we don’t accept that specific fix but want to keep track of the
47 | issue.
48 |
49 | ## Sending a Pull Request
50 |
51 | The core team is monitoring for pull requests. We will review your pull request and either merge it, request changes to
52 | it, or close it with an explanation. We’ll do our best to provide updates and feedback throughout the process.
53 |
54 | **Before submitting a pull request, please make sure the following is done:**
55 |
56 | 1. Fork [the repository](https://github.com/soc221b/zod-schema-faker) and create your branch from `main`.
57 | 2. Run `npm ci` in the repository root.
58 | 3. If you’ve fixed a bug or added code that should be tested, add tests!
59 | 4. Ensure the test suite passes (`npm run test`).
60 | 5. Format your code (`npm run format`).
61 |
62 | ## Contribution Prerequisites
63 |
64 | - You have Node installed at LTS.
65 | - You are familiar with Git.
66 |
67 | ## Development Workflow
68 |
69 | After cloning Zod-schema-faker, run `npm ci` to fetch its dependencies. Then, you can run several commands:
70 |
71 | - `npm run build` builds the library.
72 | - `npm run format` checks the code style.
73 | - `npm run test` runs the test suite.
74 |
75 | ## Style Guide
76 |
77 | We use an automatic code formatter called [Prettier](https://prettier.io/). Run `npm run format` after making any
78 | changes to the code.
79 |
80 | ## License
81 |
82 | By contributing to Zod-schema-faker, you agree that your contributions will be licensed under its MIT license.
83 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/number.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 | import { lcm } from '../utils'
7 |
8 | export function fakeNumber(
9 | schema: T,
10 | context: Context,
11 | rootFake: typeof internalFake,
12 | ): Infer {
13 | let min = Number.MIN_SAFE_INTEGER
14 | let max = Number.MAX_SAFE_INTEGER
15 | let multipleOf = undefined
16 | let int = false
17 | const format = (schema as unknown as core.$ZodNumberFormat)._zod.def.format
18 | switch (format) {
19 | case 'float32': {
20 | int = false
21 | break
22 | }
23 | case 'float64': {
24 | int = false
25 | break
26 | }
27 | case 'int32': {
28 | int = true
29 | min = Math.max(min, -2147483647)
30 | max = Math.min(max, 2147483646)
31 | break
32 | }
33 | case 'safeint': {
34 | int = true
35 | break
36 | }
37 | case 'uint32': {
38 | int = true
39 | min = Math.max(min, 0)
40 | max = Math.min(max, 4294967295)
41 | break
42 | }
43 | default: {
44 | const _: never = format
45 | break
46 | }
47 | }
48 | for (const check of (schema._zod.def.checks ?? []) as core.$ZodChecks[]) {
49 | switch (check._zod.def.check) {
50 | case 'greater_than': {
51 | const _min = Number(check._zod.def.value) + (check._zod.def.inclusive ? 0 : 0.000000000000001)
52 | min = min !== undefined ? Math.max(min, _min) : _min
53 | break
54 | }
55 | case 'less_than': {
56 | const _max = Number(check._zod.def.value) - (check._zod.def.inclusive ? 0 : 0.000000000000001)
57 | max = max !== undefined ? Math.min(max, _max) : _max
58 | break
59 | }
60 | case 'multiple_of': {
61 | const _multipleOf = Number(check._zod.def.value)
62 | multipleOf = multipleOf !== undefined ? lcm(multipleOf, _multipleOf) : _multipleOf
63 | break
64 | }
65 | case 'number_format': {
66 | const format = (check as unknown as core.$ZodNumberFormat)._zod.def.format
67 | switch (format) {
68 | case 'float32': {
69 | int = false
70 | break
71 | }
72 | case 'float64': {
73 | int = false
74 | break
75 | }
76 | case 'int32': {
77 | int = true
78 | min = Math.max(min, -2147483647)
79 | max = Math.min(max, 2147483646)
80 | break
81 | }
82 | case 'safeint': {
83 | int = true
84 | break
85 | }
86 | case 'uint32': {
87 | int = true
88 | min = Math.max(min, 0)
89 | max = Math.min(max, 4294967295)
90 | break
91 | }
92 | default: {
93 | const _: never = format
94 | break
95 | }
96 | }
97 | break
98 | }
99 | default: {
100 | const _:
101 | | 'bigint_format'
102 | | 'length_equals'
103 | | 'max_length'
104 | | 'max_size'
105 | | 'mime_type'
106 | | 'min_length'
107 | | 'min_size'
108 | | 'overwrite'
109 | | 'property'
110 | | 'size_equals'
111 | | 'string_format'
112 | | never = check._zod.def.check
113 | break
114 | }
115 | }
116 | }
117 | if (multipleOf !== undefined && multipleOf === parseInt(multipleOf.toString(), 10)) {
118 | int = true
119 | }
120 | if (int) {
121 | return getFaker().number.int({ min, max, multipleOf })
122 | } else {
123 | return getFaker().number.float({ min, max, multipleOf })
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/tests/v3/zod-array-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { describe, expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodArrayFaker } from '../../src/v3/zod-array-faker'
6 |
7 | test('ZodArrayFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodArrayFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodArrayFaker should accepts a ZodArray schema', () => {
13 | const schema = z.array(z.number())
14 | expect(() => new ZodArrayFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodArrayFaker should return a ZodArrayFaker instance', () => {
18 | const schema = z.array(z.number())
19 | const faker = new ZodArrayFaker(schema)
20 | expect(faker instanceof ZodArrayFaker).toBe(true)
21 | })
22 |
23 | test('ZodArrayFaker.fake should be a function', () => {
24 | const schema = z.array(z.number())
25 | const faker = new ZodArrayFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | test('ZodArrayFaker.fake should return array type', () => {
30 | const schema = z.array(z.number())
31 | const faker = new ZodArrayFaker(schema)
32 | expectType, number[]>>(true)
33 | })
34 |
35 | test('ZodArrayFaker.fake should return a valid data', () => {
36 | install()
37 |
38 | const schema = z.array(z.number())
39 | const faker = new ZodArrayFaker(schema)
40 | const data = faker.fake()
41 | expect(schema.safeParse(data).success).toBe(true)
42 | })
43 |
44 | test('non-empty', () => {
45 | install()
46 |
47 | const schema = z.array(z.number()).nonempty()
48 | const faker = new ZodArrayFaker(schema)
49 | const data = faker.fake()
50 | expect(schema.safeParse(data).success).toBe(true)
51 | })
52 |
53 | test('min', () => {
54 | install()
55 |
56 | const schema = z.array(z.number()).min(5)
57 | const faker = new ZodArrayFaker(schema)
58 | const data = faker.fake()
59 | expect(schema.safeParse(data).success).toBe(true)
60 | })
61 |
62 | test('max', () => {
63 | install()
64 |
65 | const schema = z.array(z.number()).max(5)
66 | const faker = new ZodArrayFaker(schema)
67 | const data = faker.fake()
68 | expect(schema.safeParse(data).success).toBe(true)
69 | })
70 |
71 | test('length', () => {
72 | install()
73 |
74 | const schema = z.array(z.number()).length(5)
75 | const faker = new ZodArrayFaker(schema)
76 | const data = faker.fake()
77 | expect(schema.safeParse(data).success).toBe(true)
78 | })
79 |
80 | describe('multiple checks of the same kind', () => {
81 | test('min', () => {
82 | install()
83 |
84 | const schema = z.array(z.number()).min(5).min(3).min(4).max(5)
85 | const faker = new ZodArrayFaker(schema)
86 | const data = faker.fake()
87 | expect(schema.safeParse(data).data?.length).toBeGreaterThanOrEqual(4)
88 | })
89 |
90 | test('max', () => {
91 | install()
92 |
93 | const schema = z.array(z.number()).max(3).max(5).max(4).min(3)
94 | const faker = new ZodArrayFaker(schema)
95 | const data = faker.fake()
96 | expect(schema.safeParse(data).data?.length).toBeLessThanOrEqual(4)
97 | })
98 | })
99 |
100 | describe('impossible case', () => {
101 | test('min > max', () => {
102 | const schema = z.array(z.number()).min(5).max(4)
103 | const faker = new ZodArrayFaker(schema)
104 | expect(() => faker.fake()).toThrow(RangeError)
105 | })
106 |
107 | test('min !== length', () => {
108 | const schema = z.array(z.number()).min(5).length(4)
109 | const faker = new ZodArrayFaker(schema)
110 | expect(() => faker.fake()).toThrow(RangeError)
111 | })
112 |
113 | test('max !== length', () => {
114 | const schema = z.array(z.number()).max(5).length(4)
115 | const faker = new ZodArrayFaker(schema)
116 | expect(() => faker.fake()).toThrow(RangeError)
117 | })
118 | })
119 |
--------------------------------------------------------------------------------
/tests/v3/zod-object-faker.test.ts:
--------------------------------------------------------------------------------
1 | import { expectType, TypeEqual } from 'ts-expect'
2 | import { describe, expect, test } from 'vitest'
3 | import { z } from 'zod/v3'
4 | import { install } from '../../src/v3'
5 | import { ZodObjectFaker } from '../../src/v3/zod-object-faker'
6 |
7 | test('ZodObjectFaker should assert parameters', () => {
8 | const invalidSchema = void 0 as any
9 | expect(() => new ZodObjectFaker(invalidSchema)).toThrow()
10 | })
11 |
12 | test('ZodObjectFaker should accepts a ZodObject schema', () => {
13 | const schema = z.object({ foo: z.number(), bar: z.string() })
14 | expect(() => new ZodObjectFaker(schema)).not.toThrow()
15 | })
16 |
17 | test('ZodObjectFaker should return a ZodObjectFaker instance', () => {
18 | const schema = z.object({ foo: z.number(), bar: z.string() })
19 | const faker = new ZodObjectFaker(schema)
20 | expect(faker instanceof ZodObjectFaker).toBe(true)
21 | })
22 |
23 | test('ZodObjectFaker.fake should be a function', () => {
24 | const schema = z.object({ foo: z.number(), bar: z.string() })
25 | const faker = new ZodObjectFaker(schema)
26 | expect(typeof faker.fake).toBe('function')
27 | })
28 |
29 | describe('default', () => {
30 | test('ZodObjectFaker.fake should return object type', () => {
31 | const schema = z.object({ foo: z.number(), bar: z.string() })
32 | const faker = new ZodObjectFaker(schema)
33 | expectType, { foo: number; bar: string }>>(true)
34 | })
35 |
36 | test('ZodObjectFaker.fake should return a valid data', () => {
37 | install()
38 |
39 | const schema = z.object({ foo: z.number(), bar: z.string() })
40 | const faker = new ZodObjectFaker(schema)
41 | const data = faker.fake()
42 | expect(schema.safeParse(data).success).toBe(true)
43 | })
44 | })
45 |
46 | describe('passthrough', () => {
47 | test('ZodObjectFaker.fake should return object type', () => {
48 | const schema = z.object({ foo: z.number(), bar: z.string() }).passthrough()
49 | const faker = new ZodObjectFaker(schema)
50 | expectType, { foo: number; bar: string } & { [k: string]: unknown }>>(true)
51 | })
52 |
53 | test('ZodObjectFaker.fake should return a valid data', () => {
54 | install()
55 |
56 | const schema = z.object({ foo: z.number(), bar: z.string() }).passthrough()
57 | const faker = new ZodObjectFaker(schema)
58 | const data = faker.fake()
59 | expect(schema.safeParse(data).success).toBe(true)
60 | })
61 |
62 | test('ZodObjectFaker.fake should sometimes return extra keys', () => {
63 | install()
64 |
65 | const schema = z.object({ foo: z.number(), bar: z.string() }).passthrough()
66 | const faker = new ZodObjectFaker(schema)
67 | while (true) {
68 | const data = faker.fake()
69 | if (Object.keys(data).length > 2) {
70 | return
71 | }
72 | }
73 | })
74 | })
75 |
76 | describe('strict', () => {
77 | test('ZodObjectFaker.fake should return object type', () => {
78 | const schema = z.object({ foo: z.number(), bar: z.string() }).strict()
79 | const faker = new ZodObjectFaker(schema)
80 | expectType, { foo: number; bar: string }>>(true)
81 | })
82 |
83 | test('ZodObjectFaker.fake should return a valid data', () => {
84 | install()
85 |
86 | const schema = z.object({ foo: z.number(), bar: z.string() }).strict()
87 | const faker = new ZodObjectFaker(schema)
88 | const data = faker.fake()
89 | expect(schema.safeParse(data).success).toBe(true)
90 | })
91 | })
92 |
93 | describe('catchall', () => {
94 | test('ZodObjectFaker.fake should return object type', () => {
95 | const schema = z.object({ foo: z.number(), bar: z.string() }).catchall(z.boolean())
96 | const faker = new ZodObjectFaker(schema)
97 | expectType<
98 | TypeEqual<
99 | ReturnType,
100 | { foo: number; bar: string } & {
101 | [k: string]: boolean
102 | }
103 | >
104 | >(true)
105 | })
106 |
107 | test('ZodObjectFaker.fake should return a valid data', () => {
108 | install()
109 |
110 | const schema = z.object({ foo: z.number(), bar: z.string() }).catchall(z.boolean())
111 | const faker = new ZodObjectFaker(schema)
112 | const data = faker.fake()
113 | expect(schema.safeParse(data).success).toBe(true)
114 | })
115 | })
116 |
--------------------------------------------------------------------------------
/src/v4/internals/schemas/string.ts:
--------------------------------------------------------------------------------
1 | import * as core from 'zod/v4/core'
2 | import { Context } from '../context'
3 | import { rootFake as internalFake } from '../fake'
4 | import { getFaker } from '../random'
5 | import { Infer } from '../type'
6 | import { unescape } from '../utils'
7 | import { fakeStringFormat } from './checks/string-format'
8 |
9 | export function fakeString