@casekit/orm2-testing 0.0.0-20250331202540 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,41 +1,40 @@
1
1
  {
2
2
  "name": "@casekit/orm2-testing",
3
3
  "description": "",
4
- "version": "0.0.0-20250331202540",
4
+ "version": "1.0.0",
5
5
  "author": "",
6
6
  "dependencies": {
7
- "@anatine/zod-mock": "^3.13.5",
8
- "es-toolkit": "^1.33.0",
9
- "@casekit/orm2-config": "0.0.0-20250331202540",
10
- "@casekit/sql": "0.0.0-20250331202540",
11
- "@casekit/orm2-schema": "0.0.0-20250331202540",
12
- "@casekit/toolbox": "0.0.0-20250331202540"
7
+ "@faker-js/faker": "^9.8.0",
8
+ "es-toolkit": "^1.39.3",
9
+ "@casekit/orm2-config": "1.0.0",
10
+ "@casekit/sql": "1.0.0",
11
+ "@casekit/toolbox": "1.0.0",
12
+ "@casekit/orm2-schema": "1.0.0"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
16
- "@types/node": "^22.13.13",
17
- "@vitest/coverage-v8": "^3.0.9",
16
+ "@types/node": "^24.0.3",
17
+ "@vitest/coverage-v8": "^3.2.4",
18
18
  "prettier": "^3.5.3",
19
- "prettier-plugin-svelte": "^3.3.3",
19
+ "prettier-plugin-svelte": "^3.4.0",
20
20
  "vite-tsconfig-paths": "^5.1.4",
21
- "vitest": "^3.0.9",
22
- "@casekit/tsconfig": "0.0.0-20250331202540",
23
- "@casekit/prettier-config": "0.0.0-20250331202540"
21
+ "vitest": "^3.2.4",
22
+ "@casekit/prettier-config": "1.0.0",
23
+ "@casekit/tsconfig": "1.0.0"
24
24
  },
25
25
  "exports": {
26
- ".": "./build/index.js"
26
+ ".": "./src/index.ts"
27
27
  },
28
28
  "files": [
29
- "/build"
29
+ "/src"
30
30
  ],
31
31
  "imports": {
32
- "#*": "./build/*"
32
+ "#*": "./src/*"
33
33
  },
34
34
  "keywords": [],
35
35
  "license": "ISC",
36
- "main": "index.js",
37
36
  "peerDependencies": {
38
- "zod": "^3.24.2"
37
+ "zod": "^4.0.17"
39
38
  },
40
39
  "prettier": "@casekit/prettier-config",
41
40
  "type": "module",
package/src/factory.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { mapValues, uniq } from "es-toolkit";
2
+ import { z } from "zod";
3
+
4
+ import { NormalizedConfig } from "@casekit/orm2-config";
5
+ import { ModelDefinitions, ModelName, ModelType } from "@casekit/orm2-schema";
6
+
7
+ import { generate } from "./generate.js";
8
+
9
+ export type Factory<Models extends ModelDefinitions> = {
10
+ [M in ModelName<Models>]: (
11
+ overrides?: Partial<ModelType<Models[M]>>,
12
+ ) => ModelType<Models[M]>;
13
+ };
14
+
15
+ export const makeFactory = <Models extends ModelDefinitions>(
16
+ config: NormalizedConfig,
17
+ ): Factory<Models> => {
18
+ return mapValues(config.models, (model) => {
19
+ // We never want to generate foreign key values
20
+ // as there's no way for us to know how to generate
21
+ // valid ones. This is up to the user to provide.
22
+ const fkOverrides = Object.fromEntries(
23
+ uniq(model.foreignKeys.flatMap((fk) => fk.fields)).map((fk) => [
24
+ fk,
25
+ null,
26
+ ]),
27
+ );
28
+
29
+ const fields = Object.entries(model.fields)
30
+ .filter(([_, f]) => !f.provided)
31
+ .map(([name, f]) => [
32
+ name,
33
+ f.default
34
+ ? f.zodSchema.optional()
35
+ : f.nullable
36
+ ? f.zodSchema.nullable()
37
+ : f.zodSchema,
38
+ ]);
39
+
40
+ const schema = z.object(Object.fromEntries(fields));
41
+ return (overrides: Record<string, unknown>) => ({
42
+ ...generate(schema),
43
+ ...fkOverrides,
44
+ ...overrides,
45
+ });
46
+ }) as Factory<Models>;
47
+ };
@@ -0,0 +1,238 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { z } from "zod";
3
+
4
+ import { generate } from "./generate.js";
5
+
6
+ describe("generate", () => {
7
+ it("generates a simple object with string fields", () => {
8
+ const schema = z.object({
9
+ name: z.string(),
10
+ description: z.string(),
11
+ });
12
+
13
+ const result = generate(schema);
14
+
15
+ expect(result).toEqual({
16
+ name: expect.any(String),
17
+ description: expect.any(String),
18
+ });
19
+ });
20
+
21
+ it("generates an object with various field types", () => {
22
+ const schema = z.object({
23
+ id: z.uuid(),
24
+ name: z.string(),
25
+ age: z.number(),
26
+ isActive: z.boolean(),
27
+ createdAt: z.date(),
28
+ balance: z.bigint(),
29
+ });
30
+
31
+ const result = generate(schema);
32
+
33
+ expect(result).toEqual({
34
+ id: expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),
35
+ name: expect.any(String),
36
+ age: expect.any(Number),
37
+ isActive: expect.any(Boolean),
38
+ createdAt: expect.any(Date),
39
+ balance: expect.any(Number),
40
+ });
41
+ });
42
+
43
+ it("generates nested objects", () => {
44
+ const schema = z.object({
45
+ user: z.object({
46
+ name: z.string(),
47
+ email: z.email(),
48
+ }),
49
+ settings: z.object({
50
+ notifications: z.boolean(),
51
+ theme: z.string(),
52
+ }),
53
+ });
54
+
55
+ const result = generate(schema);
56
+
57
+ expect(result).toEqual({
58
+ user: {
59
+ name: expect.any(String),
60
+ email: expect.stringMatching(/^[^\s@]+@[^\s@]+\.[^\s@]+$/),
61
+ },
62
+ settings: {
63
+ notifications: expect.any(Boolean),
64
+ theme: expect.any(String),
65
+ },
66
+ });
67
+ });
68
+
69
+ it("generates arrays", () => {
70
+ const schema = z.object({
71
+ tags: z.array(z.string()),
72
+ scores: z.array(z.number()),
73
+ });
74
+
75
+ const result = generate(schema);
76
+
77
+ expect(result.tags).toEqual(expect.arrayContaining([expect.any(String)]));
78
+ expect(result.scores).toEqual(expect.arrayContaining([expect.any(Number)]));
79
+ });
80
+
81
+ it("generates records", () => {
82
+ const schema = z.object({
83
+ metadata: z.record(z.string(), z.string()),
84
+ counts: z.record(z.number(), z.string()),
85
+ });
86
+
87
+ const result = generate(schema);
88
+
89
+ expect(result).toEqual({
90
+ metadata: {
91
+ a: expect.any(String),
92
+ b: expect.any(String),
93
+ c: expect.any(String),
94
+ },
95
+ counts: {
96
+ a: expect.any(String),
97
+ b: expect.any(String),
98
+ c: expect.any(String),
99
+ },
100
+ });
101
+ });
102
+
103
+ it("generates arrays of objects", () => {
104
+ const schema = z.object({
105
+ users: z.array(
106
+ z.object({
107
+ id: z.string().uuid(),
108
+ name: z.string(),
109
+ }),
110
+ ),
111
+ });
112
+
113
+ const result = generate(schema);
114
+
115
+ expect(result).toEqual({
116
+ users: expect.arrayContaining([
117
+ expect.objectContaining({
118
+ id: expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),
119
+ name: expect.any(String),
120
+ }),
121
+ ]),
122
+ });
123
+ });
124
+
125
+ it("applies overrides to generated data", () => {
126
+ const schema = z.object({
127
+ name: z.string(),
128
+ age: z.number(),
129
+ isActive: z.boolean(),
130
+ });
131
+
132
+ const result = generate(schema, {
133
+ name: "John Doe",
134
+ age: 30,
135
+ });
136
+
137
+ expect(result).toEqual({
138
+ name: "John Doe",
139
+ age: 30,
140
+ isActive: expect.any(Boolean),
141
+ });
142
+ });
143
+
144
+ it("handles partial overrides", () => {
145
+ const schema = z.object({
146
+ id: z.string().uuid(),
147
+ name: z.string(),
148
+ email: z.string(),
149
+ });
150
+
151
+ const result = generate(schema, {
152
+ name: "Jane Smith",
153
+ });
154
+
155
+ expect(result).toEqual({
156
+ id: expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),
157
+ name: "Jane Smith",
158
+ email: expect.any(String),
159
+ });
160
+ });
161
+
162
+ it("generates deeply nested structures", () => {
163
+ const schema = z.object({
164
+ level1: z.object({
165
+ level2: z.object({
166
+ level3: z.object({
167
+ value: z.string(),
168
+ }),
169
+ }),
170
+ }),
171
+ });
172
+
173
+ const result = generate(schema);
174
+
175
+ expect(result).toEqual({
176
+ level1: {
177
+ level2: {
178
+ level3: {
179
+ value: expect.any(String),
180
+ },
181
+ },
182
+ },
183
+ });
184
+ });
185
+
186
+ it("handles unknown schema types by returning undefined", () => {
187
+ const customSchema = z.custom<string>((val) => typeof val === "string");
188
+ const schema = z.object({
189
+ custom: customSchema,
190
+ });
191
+
192
+ const result = generate(schema);
193
+
194
+ expect(result).toEqual({
195
+ custom: undefined,
196
+ });
197
+ });
198
+
199
+ it("generates complex mixed structures", () => {
200
+ const schema = z.object({
201
+ company: z.object({
202
+ name: z.string(),
203
+ founded: z.date(),
204
+ employees: z.array(
205
+ z.object({
206
+ id: z.uuid(),
207
+ name: z.string(),
208
+ email: z.string(),
209
+ active: z.boolean(),
210
+ }),
211
+ ),
212
+ metadata: z.record(z.string(), z.string()),
213
+ }),
214
+ });
215
+
216
+ const result = generate(schema);
217
+
218
+ expect(result).toEqual({
219
+ company: {
220
+ name: expect.any(String),
221
+ founded: expect.any(Date),
222
+ employees: expect.arrayContaining([
223
+ expect.objectContaining({
224
+ id: expect.stringMatching(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),
225
+ name: expect.any(String),
226
+ email: expect.any(String),
227
+ active: expect.any(Boolean),
228
+ }),
229
+ ]),
230
+ metadata: {
231
+ a: expect.any(String),
232
+ b: expect.any(String),
233
+ c: expect.any(String),
234
+ },
235
+ },
236
+ });
237
+ });
238
+ });
@@ -0,0 +1,49 @@
1
+ import { faker } from "@faker-js/faker";
2
+ import z, { ZodObject, ZodType } from "zod";
3
+ import { $ZodType } from "zod/v4/core";
4
+
5
+ const generateInner = <T>(schema: $ZodType<T>): unknown => {
6
+ if (schema instanceof ZodObject) {
7
+ const shape = schema.shape;
8
+ const result: Record<string, unknown> = {};
9
+ for (const key in shape) {
10
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
11
+ result[key] = generateInner(shape[key]);
12
+ }
13
+ return result as T;
14
+ } else if (schema instanceof z.ZodOptional) {
15
+ return generateInner(schema.def.innerType);
16
+ } else if (schema instanceof z.ZodRecord) {
17
+ return {
18
+ a: generateInner(schema.valueType),
19
+ b: generateInner(schema.valueType),
20
+ c: generateInner(schema.valueType),
21
+ };
22
+ } else if (schema instanceof z.ZodEnum) {
23
+ return faker.helpers.arrayElement(Object.values(schema.def.entries));
24
+ } else if (schema instanceof z.ZodArray) {
25
+ return faker.helpers.multiple(() => generateInner(schema.element), {
26
+ count: { min: 1, max: 3 },
27
+ });
28
+ } else if (schema instanceof z.ZodDate) {
29
+ return faker.date.past();
30
+ } else if (schema instanceof z.ZodBoolean) {
31
+ return faker.datatype.boolean();
32
+ } else if (schema instanceof z.ZodUUID) {
33
+ return faker.string.uuid();
34
+ } else if (schema instanceof z.ZodString) {
35
+ return faker.lorem.word();
36
+ } else if (schema instanceof z.ZodEmail) {
37
+ return faker.internet.exampleEmail();
38
+ } else if (schema instanceof z.ZodBigInt) {
39
+ return faker.number.int({ min: 1, max: 100 });
40
+ } else if (schema instanceof z.ZodNumber) {
41
+ return faker.number.int({ min: 1, max: 100 });
42
+ } else {
43
+ return undefined;
44
+ }
45
+ };
46
+
47
+ export const generate = <T>(schema: ZodType<T>, overrides?: Partial<T>): T => {
48
+ return { ...(generateInner(schema) as T), ...overrides };
49
+ };
@@ -1,7 +0,0 @@
1
- import { GenerateMockOptions } from "@anatine/zod-mock";
2
- import { NormalizedConfig } from "@casekit/orm2-config";
3
- import { ModelDefinitions, ModelName, ModelType } from "@casekit/orm2-schema";
4
- export type Factory<Models extends ModelDefinitions> = {
5
- [M in ModelName<Models>]: (overrides?: Partial<ModelType<Models[M]>>) => ModelType<Models[M]>;
6
- };
7
- export declare const makeFactory: <Models extends ModelDefinitions>(config: NormalizedConfig, options?: GenerateMockOptions) => Factory<Models>;
package/build/factory.js DELETED
@@ -1,30 +0,0 @@
1
- import { generateMock } from "@anatine/zod-mock";
2
- import { mapValues, uniq } from "es-toolkit";
3
- import { z } from "zod";
4
- export const makeFactory = (config, options) => {
5
- return mapValues(config.models, (model) => {
6
- // We never want to generate foreign key values
7
- // as there's no way for us to know how to generate
8
- // valid ones. This is up to the user to provide.
9
- const fkOverrides = Object.fromEntries(uniq(model.foreignKeys.flatMap((fk) => fk.fields)).map((fk) => [
10
- fk,
11
- null,
12
- ]));
13
- const fields = Object.entries(model.fields)
14
- .filter(([_, f]) => !f.provided)
15
- .map(([name, f]) => [
16
- name,
17
- f.default
18
- ? f.zodSchema.optional()
19
- : f.nullable
20
- ? f.zodSchema.nullable()
21
- : f.zodSchema,
22
- ]);
23
- const schema = z.object(Object.fromEntries(fields));
24
- return (overrides) => ({
25
- ...generateMock(schema, options),
26
- ...fkOverrides,
27
- ...overrides,
28
- });
29
- });
30
- };
package/build/index.js DELETED
@@ -1 +0,0 @@
1
- export { makeFactory } from "./factory.js";
File without changes