@schmock/faker 2.2.3 → 2.3.1

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/constants.d.ts +82 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/field-mappings.d.ts.map +1 -1
  6. package/dist/field-name-matcher.d.ts +19 -0
  7. package/dist/field-name-matcher.d.ts.map +1 -1
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +4 -1
  11. package/dist/jsf-config.d.ts +27 -2
  12. package/dist/jsf-config.d.ts.map +1 -1
  13. package/dist/output-limits.d.ts +3 -0
  14. package/dist/output-limits.d.ts.map +1 -0
  15. package/dist/overrides.d.ts +2 -1
  16. package/dist/overrides.d.ts.map +1 -1
  17. package/dist/schema-children.d.ts +14 -0
  18. package/dist/schema-children.d.ts.map +1 -0
  19. package/dist/schema-enhancement.d.ts +1 -0
  20. package/dist/schema-enhancement.d.ts.map +1 -1
  21. package/dist/validation.d.ts +24 -5
  22. package/dist/validation.d.ts.map +1 -1
  23. package/package.json +19 -9
  24. package/dist/constants.js +0 -8
  25. package/dist/field-mappings.js +0 -1107
  26. package/dist/field-name-matcher.js +0 -149
  27. package/dist/jsf-config.js +0 -35
  28. package/dist/overrides.js +0 -131
  29. package/dist/schema-enhancement.js +0 -89
  30. package/dist/test-utils.d.ts +0 -57
  31. package/dist/test-utils.d.ts.map +0 -1
  32. package/dist/test-utils.js +0 -271
  33. package/dist/validation.js +0 -300
  34. package/src/advanced-features.test.ts +0 -912
  35. package/src/audit-faker-args.test.ts +0 -97
  36. package/src/constants.d.ts.map +0 -1
  37. package/src/constants.ts +0 -9
  38. package/src/data-quality.test.ts +0 -415
  39. package/src/error-handling.test.ts +0 -504
  40. package/src/field-mappings.test.ts +0 -351
  41. package/src/field-mappings.ts +0 -1141
  42. package/src/field-name-matcher.test.ts +0 -292
  43. package/src/field-name-matcher.ts +0 -188
  44. package/src/index.d.ts.map +0 -1
  45. package/src/index.test.ts +0 -1218
  46. package/src/index.ts +0 -168
  47. package/src/integration.test.ts +0 -634
  48. package/src/jsf-config.d.ts.map +0 -1
  49. package/src/jsf-config.ts +0 -48
  50. package/src/overrides.d.ts.map +0 -1
  51. package/src/overrides.property.test.ts +0 -172
  52. package/src/overrides.test.ts +0 -38
  53. package/src/overrides.ts +0 -176
  54. package/src/performance.test.ts +0 -494
  55. package/src/plugin-integration.test.ts +0 -575
  56. package/src/post-process.test.ts +0 -151
  57. package/src/real-world.test.ts +0 -636
  58. package/src/schema-enhancement.d.ts.map +0 -1
  59. package/src/schema-enhancement.test.ts +0 -216
  60. package/src/schema-enhancement.ts +0 -128
  61. package/src/steps/deterministic-seeds.steps.ts +0 -35
  62. package/src/steps/faker-plugin.steps.ts +0 -109
  63. package/src/test-utils.ts +0 -365
  64. package/src/validation.d.ts.map +0 -1
  65. package/src/validation.ts +0 -417
@@ -1,636 +0,0 @@
1
- import type { JSONSchema7 } from "json-schema";
2
- import { describe, expect, it } from "vitest";
3
- import { fakerPlugin, generateFromSchema } from "./index";
4
- import { validators } from "./test-utils";
5
-
6
- describe("Real-World Scenarios", () => {
7
- describe("API Response Schemas", () => {
8
- it("generates REST API list responses", async () => {
9
- const schema: JSONSchema7 = {
10
- type: "object",
11
- properties: {
12
- data: {
13
- type: "array",
14
- items: {
15
- type: "object",
16
- properties: {
17
- id: { type: "string", format: "uuid" },
18
- title: { type: "string", minLength: 1, maxLength: 200 },
19
- status: {
20
- type: "string",
21
- enum: ["draft", "published", "archived"],
22
- },
23
- author: {
24
- type: "object",
25
- properties: {
26
- id: { type: "string", format: "uuid" },
27
- name: { type: "string" },
28
- email: { type: "string", format: "email" },
29
- },
30
- required: ["id", "name"],
31
- },
32
- createdAt: { type: "string", format: "date-time" },
33
- tags: {
34
- type: "array",
35
- items: { type: "string" },
36
- maxItems: 10,
37
- },
38
- },
39
- required: ["id", "title", "status", "author", "createdAt"],
40
- },
41
- },
42
- meta: {
43
- type: "object",
44
- properties: {
45
- page: { type: "integer", minimum: 1 },
46
- perPage: { type: "integer", minimum: 1, maximum: 100 },
47
- total: { type: "integer", minimum: 0 },
48
- totalPages: { type: "integer", minimum: 0 },
49
- },
50
- required: ["page", "perPage", "total", "totalPages"],
51
- },
52
- },
53
- required: ["data", "meta"],
54
- };
55
-
56
- const result = await generateFromSchema({ schema });
57
-
58
- expect(result).toHaveProperty("data");
59
- expect(result).toHaveProperty("meta");
60
- expect(Array.isArray(result.data)).toBe(true);
61
-
62
- // Verify structure
63
- if (result.data.length > 0) {
64
- const item = result.data[0];
65
- expect(validators.appearsToBeFromCategory([item.id], "uuid")).toBe(
66
- true,
67
- );
68
- expect(item.title.length).toBeGreaterThan(0);
69
- expect(["draft", "published", "archived"]).toContain(item.status);
70
- expect(
71
- validators.appearsToBeFromCategory([item.author.email], "email"),
72
- ).toBe(true);
73
- }
74
-
75
- // Meta should make sense
76
- expect(result.meta.page).toBeGreaterThanOrEqual(1);
77
- expect(result.meta.perPage).toBeGreaterThanOrEqual(1);
78
- expect(result.meta.total).toBeGreaterThanOrEqual(0);
79
- });
80
-
81
- it("generates GraphQL-style responses", async () => {
82
- const schema: JSONSchema7 = {
83
- type: "object",
84
- properties: {
85
- data: {
86
- type: "object",
87
- properties: {
88
- user: {
89
- type: "object",
90
- properties: {
91
- id: { type: "string" },
92
- username: { type: "string" },
93
- profile: {
94
- type: "object",
95
- properties: {
96
- firstName: { type: "string" },
97
- lastName: { type: "string" },
98
- avatar: { type: "string", format: "uri" },
99
- },
100
- },
101
- posts: {
102
- type: "array",
103
- items: {
104
- type: "object",
105
- properties: {
106
- id: { type: "string" },
107
- title: { type: "string" },
108
- content: { type: "string" },
109
- publishedAt: { type: "string", format: "date-time" },
110
- },
111
- },
112
- },
113
- },
114
- },
115
- },
116
- },
117
- errors: {
118
- type: "array",
119
- items: {
120
- type: "object",
121
- properties: {
122
- message: { type: "string" },
123
- path: { type: "array", items: { type: "string" } },
124
- extensions: { type: "object" },
125
- },
126
- },
127
- },
128
- },
129
- };
130
-
131
- const result = await generateFromSchema({ schema });
132
-
133
- if (result.data?.user) {
134
- expect(result.data.user).toHaveProperty("id");
135
- expect(result.data.user).toHaveProperty("username");
136
-
137
- if (result.data.user.profile) {
138
- expect(typeof result.data.user.profile.firstName).toBe("string");
139
- expect(result.data.user.profile.firstName.length).toBeGreaterThan(0);
140
- }
141
-
142
- if (result.data.user.posts && result.data.user.posts.length > 0) {
143
- expect(result.data.user.posts[0]).toHaveProperty("title");
144
- }
145
- }
146
- });
147
-
148
- it("generates webhook payloads", async () => {
149
- const schema: JSONSchema7 = {
150
- type: "object",
151
- properties: {
152
- event: {
153
- type: "string",
154
- enum: ["order.created", "order.updated", "order.cancelled"],
155
- },
156
- timestamp: { type: "string", format: "date-time" },
157
- data: {
158
- type: "object",
159
- properties: {
160
- orderId: { type: "string", format: "uuid" },
161
- customerId: { type: "string", format: "uuid" },
162
- amount: { type: "number", minimum: 0 },
163
- currency: { type: "string", enum: ["USD", "EUR", "GBP"] },
164
- items: {
165
- type: "array",
166
- items: {
167
- type: "object",
168
- properties: {
169
- productId: { type: "string" },
170
- quantity: { type: "integer", minimum: 1 },
171
- price: { type: "number", minimum: 0 },
172
- },
173
- },
174
- },
175
- },
176
- },
177
- signature: { type: "string", pattern: "^[a-f0-9]{64}$" },
178
- },
179
- required: ["event", "timestamp", "data", "signature"],
180
- };
181
-
182
- const result = await generateFromSchema({ schema });
183
-
184
- expect(["order.created", "order.updated", "order.cancelled"]).toContain(
185
- result.event,
186
- );
187
- expect(new Date(result.timestamp).getTime()).not.toBeNaN();
188
- expect(result.signature).toMatch(/^[a-f0-9]{64}$/);
189
- expect(result.data.amount).toBeGreaterThanOrEqual(0);
190
- });
191
- });
192
-
193
- describe("Database Model Schemas", () => {
194
- it("generates user model data", async () => {
195
- const schema: JSONSchema7 = {
196
- type: "object",
197
- properties: {
198
- id: { type: "integer", minimum: 1 },
199
- username: { type: "string", pattern: "^[a-zA-Z0-9_]{3,20}$" },
200
- email: { type: "string", format: "email" },
201
- passwordHash: {
202
- type: "string",
203
- pattern: "^\\$2[aby]\\$[0-9]{2}\\$.{53}$",
204
- },
205
- profile: {
206
- type: "object",
207
- properties: {
208
- firstName: { type: "string", maxLength: 50 },
209
- lastName: { type: "string", maxLength: 50 },
210
- bio: { type: "string", maxLength: 500 },
211
- dateOfBirth: { type: "string", format: "date" },
212
- phoneNumber: { type: "string", pattern: "^\\+?[1-9]\\d{1,14}$" },
213
- },
214
- },
215
- settings: {
216
- type: "object",
217
- properties: {
218
- theme: { type: "string", enum: ["light", "dark", "auto"] },
219
- language: { type: "string", enum: ["en", "es", "fr", "de"] },
220
- emailNotifications: { type: "boolean" },
221
- twoFactorEnabled: { type: "boolean" },
222
- },
223
- },
224
- createdAt: { type: "string", format: "date-time" },
225
- updatedAt: { type: "string", format: "date-time" },
226
- lastLoginAt: {
227
- oneOf: [{ type: "string", format: "date-time" }, { type: "null" }],
228
- },
229
- },
230
- required: [
231
- "id",
232
- "username",
233
- "email",
234
- "passwordHash",
235
- "createdAt",
236
- "updatedAt",
237
- ],
238
- };
239
-
240
- const result = await generateFromSchema({ schema });
241
-
242
- expect(result.id).toBeGreaterThanOrEqual(1);
243
- expect(result.username).toMatch(/^[a-zA-Z0-9_]{3,20}$/);
244
- expect(validators.appearsToBeFromCategory([result.email], "email")).toBe(
245
- true,
246
- );
247
- expect(result.passwordHash).toMatch(/^\$2[aby]\$[0-9]{2}\$.{53}$/);
248
-
249
- // Dates should be valid
250
- const created = new Date(result.createdAt);
251
- const updated = new Date(result.updatedAt);
252
- expect(created.getTime()).not.toBeNaN();
253
- expect(updated.getTime()).not.toBeNaN();
254
- });
255
-
256
- it("generates product catalog data", async () => {
257
- const schema: JSONSchema7 = {
258
- type: "object",
259
- properties: {
260
- sku: { type: "string", pattern: "^[A-Z]{3}-[0-9]{6}$" },
261
- name: { type: "string", minLength: 1, maxLength: 200 },
262
- description: { type: "string", maxLength: 2000 },
263
- price: {
264
- type: "object",
265
- properties: {
266
- amount: { type: "number", minimum: 0, multipleOf: 0.01 },
267
- currency: { type: "string", enum: ["USD", "EUR", "GBP"] },
268
- },
269
- required: ["amount", "currency"],
270
- },
271
- inventory: {
272
- type: "object",
273
- properties: {
274
- inStock: { type: "integer", minimum: 0 },
275
- reserved: { type: "integer", minimum: 0 },
276
- available: { type: "integer" },
277
- },
278
- },
279
- categories: {
280
- type: "array",
281
- items: { type: "string" },
282
- minItems: 1,
283
- maxItems: 5,
284
- },
285
- attributes: {
286
- type: "object",
287
- additionalProperties: { type: "string" },
288
- },
289
- },
290
- };
291
-
292
- const result = await generateFromSchema({ schema });
293
-
294
- expect(result.sku).toMatch(/^[A-Z]{3}-[0-9]{6}$/);
295
- expect(result.name.length).toBeGreaterThan(0);
296
- expect(result.price.amount).toBeGreaterThanOrEqual(0);
297
- expect(["USD", "EUR", "GBP"]).toContain(result.price.currency);
298
-
299
- if (result.inventory) {
300
- expect(result.inventory.inStock).toBeGreaterThanOrEqual(0);
301
- expect(result.inventory.reserved).toBeGreaterThanOrEqual(0);
302
- }
303
- });
304
- });
305
-
306
- describe("Configuration Schemas", () => {
307
- it("generates application config", async () => {
308
- const schema: JSONSchema7 = {
309
- type: "object",
310
- properties: {
311
- app: {
312
- type: "object",
313
- properties: {
314
- name: { type: "string" },
315
- version: { type: "string", pattern: "^\\d+\\.\\d+\\.\\d+$" },
316
- environment: {
317
- type: "string",
318
- enum: ["development", "staging", "production"],
319
- },
320
- debug: { type: "boolean" },
321
- },
322
- required: ["name", "version", "environment"],
323
- },
324
- server: {
325
- type: "object",
326
- properties: {
327
- host: { type: "string", format: "hostname" },
328
- port: { type: "integer", minimum: 1, maximum: 65535 },
329
- ssl: {
330
- type: "object",
331
- properties: {
332
- enabled: { type: "boolean" },
333
- cert: { type: "string" },
334
- key: { type: "string" },
335
- },
336
- },
337
- },
338
- },
339
- database: {
340
- type: "object",
341
- properties: {
342
- type: { type: "string", enum: ["postgres", "mysql", "mongodb"] },
343
- host: { type: "string" },
344
- port: { type: "integer" },
345
- name: { type: "string" },
346
- pool: {
347
- type: "object",
348
- properties: {
349
- min: { type: "integer", minimum: 0 },
350
- max: { type: "integer", minimum: 1 },
351
- },
352
- },
353
- },
354
- },
355
- },
356
- };
357
-
358
- const result = await generateFromSchema({ schema });
359
-
360
- if (result.app) {
361
- expect(result.app.version).toMatch(/^\d+\.\d+\.\d+$/);
362
- expect(["development", "staging", "production"]).toContain(
363
- result.app.environment,
364
- );
365
- }
366
-
367
- if (result.server?.port) {
368
- expect(result.server.port).toBeGreaterThanOrEqual(1);
369
- expect(result.server.port).toBeLessThanOrEqual(65535);
370
- }
371
- });
372
-
373
- it("generates OpenAPI schema definitions", async () => {
374
- const schema: JSONSchema7 = {
375
- type: "object",
376
- properties: {
377
- openapi: { type: "string", const: "3.0.0" },
378
- info: {
379
- type: "object",
380
- properties: {
381
- title: { type: "string" },
382
- version: { type: "string" },
383
- description: { type: "string" },
384
- },
385
- required: ["title", "version"],
386
- },
387
- servers: {
388
- type: "array",
389
- items: {
390
- type: "object",
391
- properties: {
392
- url: { type: "string", format: "uri" },
393
- description: { type: "string" },
394
- },
395
- required: ["url"],
396
- },
397
- },
398
- paths: {
399
- type: "object",
400
- additionalProperties: {
401
- type: "object",
402
- properties: {
403
- get: { type: "object" },
404
- post: { type: "object" },
405
- put: { type: "object" },
406
- delete: { type: "object" },
407
- },
408
- },
409
- },
410
- },
411
- required: ["openapi", "info", "paths"],
412
- };
413
-
414
- const result = await generateFromSchema({ schema });
415
-
416
- expect(result.openapi).toBe("3.0.0");
417
- expect(result.info).toHaveProperty("title");
418
- expect(result.info).toHaveProperty("version");
419
- expect(result.paths).toBeDefined();
420
- });
421
- });
422
-
423
- describe("Form Data Schemas", () => {
424
- it("generates user registration form data", async () => {
425
- const schema: JSONSchema7 = {
426
- type: "object",
427
- properties: {
428
- username: {
429
- type: "string",
430
- minLength: 3,
431
- maxLength: 20,
432
- pattern: "^[a-zA-Z0-9_]+$",
433
- },
434
- email: {
435
- type: "string",
436
- format: "email",
437
- },
438
- password: {
439
- type: "string",
440
- minLength: 8,
441
- maxLength: 128,
442
- },
443
- confirmPassword: {
444
- type: "string",
445
- minLength: 8,
446
- maxLength: 128,
447
- },
448
- profile: {
449
- type: "object",
450
- properties: {
451
- firstName: { type: "string", maxLength: 50 },
452
- lastName: { type: "string", maxLength: 50 },
453
- dateOfBirth: { type: "string", format: "date" },
454
- country: { type: "string" },
455
- newsletter: { type: "boolean" },
456
- },
457
- },
458
- termsAccepted: { type: "boolean", const: true },
459
- },
460
- required: [
461
- "username",
462
- "email",
463
- "password",
464
- "confirmPassword",
465
- "termsAccepted",
466
- ],
467
- };
468
-
469
- const result = await generateFromSchema({ schema });
470
-
471
- expect(result.username).toMatch(/^[a-zA-Z0-9_]+$/);
472
- expect(result.username.length).toBeGreaterThanOrEqual(3);
473
- expect(validators.appearsToBeFromCategory([result.email], "email")).toBe(
474
- true,
475
- );
476
- expect(result.password.length).toBeGreaterThanOrEqual(8);
477
- expect(result.termsAccepted).toBe(true);
478
- });
479
-
480
- it("generates complex survey responses", async () => {
481
- const schema: JSONSchema7 = {
482
- type: "object",
483
- properties: {
484
- respondentId: { type: "string", format: "uuid" },
485
- submittedAt: { type: "string", format: "date-time" },
486
- responses: {
487
- type: "array",
488
- items: {
489
- type: "object",
490
- properties: {
491
- questionId: { type: "string" },
492
- type: {
493
- type: "string",
494
- enum: ["text", "choice", "scale", "multiselect"],
495
- },
496
- answer: {
497
- oneOf: [
498
- { type: "string" },
499
- { type: "number" },
500
- { type: "array", items: { type: "string" } },
501
- ],
502
- },
503
- },
504
- required: ["questionId", "type", "answer"],
505
- },
506
- },
507
- metadata: {
508
- type: "object",
509
- properties: {
510
- duration: { type: "integer", minimum: 0 },
511
- device: { type: "string", enum: ["desktop", "mobile", "tablet"] },
512
- browser: { type: "string" },
513
- },
514
- },
515
- },
516
- };
517
-
518
- const result = await generateFromSchema({ schema });
519
-
520
- expect(
521
- validators.appearsToBeFromCategory([result.respondentId], "uuid"),
522
- ).toBe(true);
523
- expect(new Date(result.submittedAt).getTime()).not.toBeNaN();
524
-
525
- if (result.responses && result.responses.length > 0) {
526
- result.responses.forEach((response) => {
527
- expect(["text", "choice", "scale", "multiselect"]).toContain(
528
- response.type,
529
- );
530
- expect(response).toHaveProperty("answer");
531
- });
532
- }
533
- });
534
- });
535
-
536
- describe("Integration with Schmock", () => {
537
- it("works with schmock route handlers", async () => {
538
- const plugin = fakerPlugin({
539
- schema: {
540
- type: "object",
541
- properties: {
542
- users: {
543
- type: "array",
544
- items: {
545
- type: "object",
546
- properties: {
547
- id: { type: "string", format: "uuid" },
548
- name: { type: "string" },
549
- email: { type: "string", format: "email" },
550
- },
551
- },
552
- },
553
- _links: {
554
- type: "object",
555
- properties: {
556
- self: { type: "string", format: "uri" },
557
- next: { type: "string", format: "uri" },
558
- prev: { type: "string", format: "uri" },
559
- },
560
- },
561
- },
562
- },
563
- count: 10,
564
- });
565
-
566
- const context = {
567
- method: "GET",
568
- path: "/api/users",
569
- params: {},
570
- query: { page: "2", limit: "10" },
571
- state: {},
572
- headers: {},
573
- body: null,
574
- route: {},
575
- };
576
-
577
- const result = await plugin.process(context);
578
-
579
- expect(result.response).toHaveProperty("users");
580
- expect(Array.isArray(result.response.users)).toBe(true);
581
-
582
- if (result.response.users.length > 0) {
583
- const user = result.response.users[0];
584
- expect(validators.appearsToBeFromCategory([user.id], "uuid")).toBe(
585
- true,
586
- );
587
- expect(validators.appearsToBeFromCategory([user.email], "email")).toBe(
588
- true,
589
- );
590
- }
591
- });
592
-
593
- it("integrates with template overrides", async () => {
594
- const plugin = fakerPlugin({
595
- schema: {
596
- type: "object",
597
- properties: {
598
- orderId: { type: "string" },
599
- customerId: { type: "string" },
600
- total: { type: "number" },
601
- status: { type: "string" },
602
- createdAt: { type: "string" },
603
- },
604
- },
605
- overrides: {
606
- orderId: "{{params.orderId}}",
607
- customerId: "{{state.user.id}}",
608
- status: "pending",
609
- createdAt: "{{state.timestamp}}",
610
- },
611
- });
612
-
613
- const context = {
614
- method: "GET",
615
- path: "/api/orders/order-123",
616
- params: { orderId: "order-123" },
617
- query: {},
618
- state: new Map(),
619
- routeState: {
620
- user: { id: "customer-456" },
621
- timestamp: "2024-01-01T12:00:00Z",
622
- },
623
- headers: {},
624
- body: null,
625
- route: {},
626
- };
627
-
628
- const result = await plugin.process(context);
629
-
630
- expect(result.response.orderId).toBe("order-123");
631
- expect(result.response.customerId).toBe("customer-456");
632
- expect(result.response.status).toBe("pending");
633
- expect(result.response.createdAt).toBe("2024-01-01T12:00:00Z");
634
- });
635
- });
636
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-enhancement.d.ts","sourceRoot":"","sources":["schema-enhancement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,GAClB,WAAW,CAwBb"}