zod-v4-mocks
Version: 
Mock generator for zod v4
357 lines (302 loc) • 8.84 kB
Markdown
# zod-v4-mocks
Mock generator for zod v4
## Installation
```bash
npm install zod-v4-mocks
```
## Basic Usage
```ts
import { initGenerator } from 'zod-v4-mocks';
import { z } from 'zod';
const schema = z.string();
const generator = initGenerator({ seed: 1 });
const res = generator.generate(schema);
console.log(schema.parse(res));
```
## Usage Details
### 1. Basic Usage
The simplest way to use the library. Generate mock data from a schema.
```ts
import { z } from 'zod';
import { initGenerator } from 'zod-v4-mocks';
const basicSchema = z.object({
  id: z.uuid(),
  name: z.string(),
  email: z.email(),
  age: z.number().min(18).max(120).optional(),
  isActive: z.boolean(),
  tags: z.array(z.string()),
  createdAt: z.date(),
});
const mockUser = initGenerator().generate(basicSchema);
```
### 2. Custom Configuration
You can customize settings such as seed value, array length, and locale.
```ts
const config = {
  seed: 42,
  array: { min: 2, max: 5 },
  locale: 'ja',
} as const;
const mockUserWithConfig = initGenerator(config).generate(basicSchema);
```
The available configuration options are as follows:
```ts
interface MockConfig {
  /**
   * @default [en, base] from faker.js
   */
  locale?: LocaleType | LocaleType[];
  /**
   * @default generateMersenne53Randomizer() from faker.js
   */
  randomizer?: Randomizer;
  /**
   * @default 1
   */
  seed: number;
  /**
   * @default { min: 1, max: 3 }
   */
  array: { min: number; max: number };
  /**
   * @default { min: 1, max: 3 }
   */
  map: { min: number; max: number };
  /**
   * @default { min: 1, max: 3 }
   */
  set: { min: number; max: number };
  /**
   * @default { min: 1, max: 3 }
   */
  record: { min: number; max: number };
  /**
   * @default 0.5
   */
  optionalProbability: number;
  /**
   * @default 0.5
   */
  nullableProbability: number;
  /**
   * @default 0.5
   */
  defaultProbability: number;
  /**
   * @default 5
   */
  lazyDepthLimit: number;
  /**
   * @description meta's attribute name which is used to generate consistent property value
   */
  consistentKey?: string;
}
```
### 3. Supply Specific Values (as Custom Generator)
You can supply fixed values for specific schema types.
```ts
const mockUserWithSupply = initGenerator()
  .supply(z.ZodString, 'custom name')
  .supply(z.ZodEmail, 'custom_email@example.com')
  .generate(basicSchema);
```
If you configure multiple values for the same ZodType condition, the first configured value takes priority.
```ts
const mockUserWithSupply = initGenerator()
  .supply(z.ZodEmail, 'prioritized_email@example.com')
  .supply(z.ZodEmail, 'not_prioritized_email@example.com')
  .generate(basicSchema);
```
### 4. Override mock generator (as Custom Generator)
You can define custom generator functions for specific schemas.
```ts
import { type CustomGeneratorType } from 'zod-v4-mocks';
const customGenerator: CustomGeneratorType = (schema, options) => {
  const { faker } = options;
  if (schema instanceof z.ZodString && schema === basicSchema.shape.name) {
    return 'custom name: ' + faker.person.fullName();
  }
};
const mockUserWithOverride = initGenerator()
  .override(customGenerator)
  .generate(basicSchema);
```
If you configure multiple values for the same ZodType condition, the first configured value takes priority.
```ts
const customGenerator: CustomGeneratorType = (schema, options) => {
  const { faker } = options;
  if (schema instanceof z.ZodEmail) {
    return 'not_prioritized_email@example.com';
  }
};
const mockUserWithSupply = initGenerator()
  .supply(z.ZodEmail, 'prioritized_email@example.com')
  .override(customGenerator)
  .generate(basicSchema);
```
### 5. Complex Schemas
Supports complex schemas including nested objects, arrays, records, and unions.
```ts
const complexSchema = z.object({
  user: z.object({
    profile: z.object({
      name: z.string(),
      bio: z.string().optional(),
    }),
    preferences: z.object({
      theme: z.enum(['light', 'dark', 'auto']),
      notifications: z.boolean().default(true),
    }),
  }),
  posts: z.array(
    z.object({
      title: z.string(),
      content: z.string(),
      publishedAt: z.date().nullable(),
      tags: z.array(z.string()),
    }),
  ),
  metadata: z.record(
    z.string(),
    z.union([z.string(), z.number(), z.boolean()]),
  ),
});
const complexMock = initGenerator().generate(complexSchema);
```
### 6. Consistent Data Generation (Register)
You can generate consistent data between related fields using metadata.
```ts
// Set the metadata key name
const consistentKey = 'name';
const UserId = z.uuid().meta({ [consistentKey]: 'UserId' });
const CommentId = z.uuid().meta({ [consistentKey]: 'CommentId' });
const PostId = z.uuid().meta({ [consistentKey]: 'PostId' });
const userSchema = z.object({
  id: UserId, // 1: Same UserId will be generated
  name: z.string(),
});
const commentSchema = z.object({
  id: CommentId,
  postId: PostId, // 2: Same PostId will be generated
  user: userSchema,
  userId: UserId, // 1: Same UserId will be generated
  value: z.string(),
});
const postSchema = z.object({
  id: PostId, // 2: Same PostId will be generated
  comments: z.array(commentSchema),
  value: z.string(),
});
const PostsResponse = z.array(postSchema);
// Register schemas first, then generate
const schemas = [CommentId, UserId, PostId];
const mock = initGenerator({ consistentKey })
  .register(schemas)
  .generate(PostsResponse);
```
This generator will generate mock like below.
```json
[
  {
    "id": "08e93b6a-0a0b-4718-81af-c91ba0c86c67",
    "comments": [
      {
        "id": "b438b6fa-765b-4706-8b22-88adb9b5534a",
        "postId": "08e93b6a-0a0b-4718-81af-c91ba0c86c67",
        "user": {
          "id": "c9b26358-a125-4ad8-ad65-52d58980fe34",
          "name": "acceptus"
        },
        "userId": "c9b26358-a125-4ad8-ad65-52d58980fe34",
        "value": "antepono"
      },
      {
        "id": "667646ef-8915-46d4-a7f8-91d98546ae8a",
        "postId": "08e93b6a-0a0b-4718-81af-c91ba0c86c67",
        "user": {
          "id": "ef49c6b2-9df1-4637-a814-e97cb0bd2c44",
          "name": "tergiversatio"
        },
        "userId": "ef49c6b2-9df1-4637-a814-e97cb0bd2c44",
        "value": "adipisci"
      },
      {
        "id": "9ad1c339-1eab-4098-922b-5b86ed5046bf",
        "postId": "08e93b6a-0a0b-4718-81af-c91ba0c86c67",
        "user": {
          "id": "1aeb77c9-19d5-4ec9-bc1d-de21266813c7",
          "name": "sum"
        },
        "userId": "1aeb77c9-19d5-4ec9-bc1d-de21266813c7",
        "value": "volup"
      }
    ],
    "value": "ut"
  },
  {
    "id": "5d26f3ee-1785-4031-93ce-04f8a07f617f",
    "comments": [
      {
        "id": "b438b6fa-765b-4706-8b22-88adb9b5534a",
        "postId": "5d26f3ee-1785-4031-93ce-04f8a07f617f",
        "user": {
          "id": "c9b26358-a125-4ad8-ad65-52d58980fe34",
          "name": "vitae"
        },
        "userId": "c9b26358-a125-4ad8-ad65-52d58980fe34",
        "value": "curtus"
      },
      {
        "id": "667646ef-8915-46d4-a7f8-91d98546ae8a",
        "postId": "5d26f3ee-1785-4031-93ce-04f8a07f617f",
        "user": {
          "id": "ef49c6b2-9df1-4637-a814-e97cb0bd2c44",
          "name": "uterque"
        },
        "userId": "ef49c6b2-9df1-4637-a814-e97cb0bd2c44",
        "value": "constans"
      },
      {
        "id": "9ad1c339-1eab-4098-922b-5b86ed5046bf",
        "postId": "5d26f3ee-1785-4031-93ce-04f8a07f617f",
        "user": {
          "id": "1aeb77c9-19d5-4ec9-bc1d-de21266813c7",
          "name": "vetus"
        },
        "userId": "1aeb77c9-19d5-4ec9-bc1d-de21266813c7",
        "value": "arcesso"
      }
    ],
    "value": "vilicus"
  }
]
```
## Unsupported Schemas
- `z.ZodCustom`
  - `.custom()` and `.instanceof()` are not supported
  - `.refine()` and `.check()` are ignored
- `.function()` is not supported
- `.nativeEnum()` is deprecated in v4
- `.promise()` is deprecated in v4
- `.superRefine()` is deprecated in v4
## Partially Supported Schemas
- `z.ZodLazy` is partially supported
  - If schema has toplevel `z.union`, this library would throw error
  - If schema has `z.tuple` or `z.intersection` anywhere, this library would cause RangeError
- `z.ZodIntersection` is partially supported
  - Same schema types are basically supported
    - But, if the elements of the Map/Set/Array/Enum/Union do not have compatible elements, then this library would throw error.
  - Different schema types are not supported in principle
    - But, ZodObject and ZodRecord would be successfully generated
    - But, ZodArray and ZodTuple would be successfully generated
  - If one element type is ZodAny/ZodUnknown, the other element type is used
## Future Support
- `.nonoptional()`
- `.catchall()`
- codec series
  - `.codec()`
  - `.json()`
  - `.stringbool()`
## Note
- In `.templateLiteral`,