@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,575 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { version as packageVersion } from "../package.json";
3
- import { fakerPlugin } from "./index";
4
- import { schemas, validators } from "./test-utils";
5
-
6
- describe("Schema Plugin Integration", () => {
7
- describe("Plugin Lifecycle", () => {
8
- it("validates schema during plugin creation", () => {
9
- // Valid schema should create plugin
10
- const validPlugin = fakerPlugin({
11
- schema: schemas.complex.user(),
12
- });
13
- expect(validPlugin).toBeDefined();
14
- expect(validPlugin.name).toBe("faker");
15
- expect(validPlugin.version).toBe(packageVersion);
16
-
17
- // Invalid schema should throw immediately
18
- expect(() => {
19
- fakerPlugin({
20
- schema: { type: "invalid" as any },
21
- });
22
- }).toThrow("Invalid schema type");
23
- });
24
-
25
- it("processes context through plugin pipeline", async () => {
26
- const plugin = fakerPlugin({
27
- schema: schemas.simple.object({
28
- requestId: { type: "string" },
29
- timestamp: { type: "string" },
30
- data: { type: "object" },
31
- }),
32
- });
33
-
34
- const context = {
35
- method: "POST",
36
- path: "/api/data",
37
- params: {},
38
- query: {},
39
- state: { requestId: "req-123" },
40
- headers: { "content-type": "application/json" },
41
- body: { value: 42 },
42
- route: { pattern: "/api/data" },
43
- };
44
-
45
- const result = await plugin.process(context);
46
-
47
- expect(result).toHaveProperty("context");
48
- expect(result).toHaveProperty("response");
49
- expect(result.context).toBe(context); // Context passed through
50
- expect(result.response).toHaveProperty("requestId");
51
- expect(result.response).toHaveProperty("timestamp");
52
- expect(result.response).toHaveProperty("data");
53
- });
54
-
55
- it("preserves existing responses when present", async () => {
56
- const plugin = fakerPlugin({
57
- schema: schemas.simple.object({ id: schemas.simple.number() }),
58
- });
59
-
60
- const context = {
61
- method: "GET",
62
- path: "/test",
63
- params: {},
64
- query: {},
65
- state: {},
66
- headers: {},
67
- body: null,
68
- route: {},
69
- };
70
-
71
- const existingResponse = {
72
- cached: true,
73
- data: [1, 2, 3],
74
- metadata: { source: "cache" },
75
- };
76
-
77
- const result = await plugin.process(context, existingResponse);
78
-
79
- expect(result.response).toBe(existingResponse);
80
- expect(result.response).toEqual(existingResponse);
81
- });
82
- });
83
-
84
- describe("Context Integration", () => {
85
- it("uses params in template overrides", async () => {
86
- const plugin = fakerPlugin({
87
- schema: schemas.simple.object({
88
- userId: { type: "string" },
89
- postId: { type: "string" },
90
- action: { type: "string" },
91
- }),
92
- overrides: {
93
- userId: "{{params.userId}}",
94
- postId: "{{params.postId}}",
95
- action: "view",
96
- },
97
- });
98
-
99
- const result = await plugin.process({
100
- method: "GET",
101
- path: "/users/123/posts/456",
102
- params: { userId: "123", postId: "456" },
103
- query: {},
104
- state: {},
105
- headers: {},
106
- body: null,
107
- route: {},
108
- });
109
-
110
- expect(result.response.userId).toBe("123"); // Template values are strings
111
- expect(result.response.postId).toBe("456");
112
- expect(result.response.action).toBe("view");
113
- });
114
-
115
- it("uses query parameters in templates", async () => {
116
- const plugin = fakerPlugin({
117
- schema: schemas.simple.object({
118
- page: { type: "number" },
119
- limit: { type: "number" },
120
- sort: { type: "string" },
121
- filter: { type: "string" },
122
- }),
123
- overrides: {
124
- page: "{{query.page}}",
125
- limit: "{{query.limit}}",
126
- sort: "{{query.sort}}",
127
- filter: "{{query.filter}}",
128
- },
129
- });
130
-
131
- const result = await plugin.process({
132
- method: "GET",
133
- path: "/api/items",
134
- params: {},
135
- query: {
136
- page: "2",
137
- limit: "50",
138
- sort: "name",
139
- filter: "active",
140
- },
141
- state: {},
142
- headers: {},
143
- body: null,
144
- route: {},
145
- });
146
-
147
- expect(result.response.page).toBe("2"); // Query values are strings
148
- expect(result.response.limit).toBe("50");
149
- expect(result.response.sort).toBe("name");
150
- expect(result.response.filter).toBe("active");
151
- });
152
-
153
- it("uses state in template processing", async () => {
154
- const plugin = fakerPlugin({
155
- schema: schemas.simple.object({
156
- currentUser: { type: "string" },
157
- sessionId: { type: "string" },
158
- permissions: { type: "array", items: { type: "string" } },
159
- }),
160
- overrides: {
161
- currentUser: "{{state.user.name}}",
162
- sessionId: "{{state.session.id}}",
163
- permissions: ["read", "write"],
164
- },
165
- });
166
-
167
- const result = await plugin.process({
168
- method: "GET",
169
- path: "/api/profile",
170
- params: {},
171
- query: {},
172
- state: new Map(),
173
- routeState: {
174
- user: { id: 1, name: "John Doe" },
175
- session: { id: "sess-123", expires: "2024-12-31" },
176
- },
177
- headers: {},
178
- body: null,
179
- route: {},
180
- });
181
-
182
- expect(result.response.currentUser).toBe("John Doe");
183
- expect(result.response.sessionId).toBe("sess-123");
184
- expect(result.response.permissions).toEqual(["read", "write"]);
185
- });
186
-
187
- it("handles missing template values gracefully", async () => {
188
- const plugin = fakerPlugin({
189
- schema: schemas.simple.object({
190
- value1: { type: "string" },
191
- value2: { type: "string" },
192
- value3: { type: "string" },
193
- }),
194
- overrides: {
195
- value1: "{{params.missing}}",
196
- value2: "{{state.nonexistent.nested}}",
197
- value3: "default",
198
- },
199
- });
200
-
201
- const result = await plugin.process({
202
- method: "GET",
203
- path: "/test",
204
- params: { other: "value" },
205
- query: {},
206
- state: new Map(),
207
- routeState: { different: "data" },
208
- headers: {},
209
- body: null,
210
- route: {},
211
- });
212
-
213
- // Missing values return original template
214
- expect(result.response.value1).toBe("{{params.missing}}");
215
- expect(result.response.value2).toBe("{{state.nonexistent.nested}}");
216
- expect(result.response.value3).toBe("default");
217
- });
218
- });
219
-
220
- describe("Array Generation with Plugin", () => {
221
- it("generates arrays with count parameter", async () => {
222
- const plugin = fakerPlugin({
223
- schema: schemas.simple.array(
224
- schemas.simple.object({
225
- id: { type: "number" },
226
- name: { type: "string" },
227
- }),
228
- ),
229
- count: 5,
230
- });
231
-
232
- const result = await plugin.process({
233
- method: "GET",
234
- path: "/api/items",
235
- params: {},
236
- query: {},
237
- state: {},
238
- headers: {},
239
- body: null,
240
- route: {},
241
- });
242
-
243
- expect(Array.isArray(result.response)).toBe(true);
244
- expect(result.response).toHaveLength(5);
245
- result.response.forEach((item) => {
246
- expect(item).toHaveProperty("id");
247
- expect(item).toHaveProperty("name");
248
- });
249
- });
250
-
251
- it("applies overrides to array items", async () => {
252
- const plugin = fakerPlugin({
253
- schema: schemas.simple.array(
254
- schemas.simple.object({
255
- index: { type: "number" },
256
- category: { type: "string" },
257
- }),
258
- ),
259
- count: 3,
260
- overrides: {
261
- category: "{{state.defaultCategory}}",
262
- },
263
- });
264
-
265
- const result = await plugin.process({
266
- method: "GET",
267
- path: "/api/items",
268
- params: {},
269
- query: {},
270
- state: new Map(),
271
- routeState: { defaultCategory: "electronics" },
272
- headers: {},
273
- body: null,
274
- route: {},
275
- });
276
-
277
- expect(result.response).toHaveLength(3);
278
- result.response.forEach((item) => {
279
- expect(item.category).toBe("electronics");
280
- });
281
- });
282
- });
283
-
284
- describe("Error Handling in Plugin", () => {
285
- it("wraps generation errors with context", async () => {
286
- const plugin = fakerPlugin({
287
- schema: {
288
- type: "string",
289
- pattern: "[", // Invalid regex
290
- },
291
- });
292
-
293
- const context = {
294
- method: "GET",
295
- path: "/api/test/123",
296
- params: { id: "123" },
297
- query: {},
298
- state: {},
299
- headers: {},
300
- body: null,
301
- route: {},
302
- };
303
-
304
- try {
305
- await plugin.process(context);
306
- expect.fail("Should have thrown");
307
- } catch (error: any) {
308
- // Should throw some kind of error for invalid pattern
309
- expect(error).toBeDefined();
310
- expect(error.name).toContain("Error");
311
- }
312
- });
313
-
314
- it("handles null or undefined context properties", async () => {
315
- const plugin = fakerPlugin({
316
- schema: schemas.simple.object({
317
- data: { type: "string" },
318
- }),
319
- });
320
-
321
- // Should not crash with null/undefined properties
322
- const result = await plugin.process({
323
- method: "GET",
324
- path: "/test",
325
- params: null as any,
326
- query: undefined as any,
327
- state: null as any,
328
- headers: {},
329
- body: null,
330
- route: {},
331
- });
332
-
333
- expect(result.response).toHaveProperty("data");
334
- expect(typeof result.response.data).toBe("string");
335
- });
336
- });
337
-
338
- describe("Complex Schema Scenarios", () => {
339
- it("handles conditional schemas in plugin", async () => {
340
- const plugin = fakerPlugin({
341
- schema: {
342
- type: "object",
343
- properties: {
344
- type: { type: "string", enum: ["user", "admin"] },
345
- data: { type: "object" },
346
- },
347
- required: ["type", "data"],
348
- },
349
- });
350
-
351
- const result = await plugin.process({
352
- method: "GET",
353
- path: "/api/profile",
354
- params: {},
355
- query: {},
356
- state: {},
357
- headers: {},
358
- body: null,
359
- route: {},
360
- });
361
-
362
- expect(["user", "admin"]).toContain(result.response.type);
363
- expect(result.response).toHaveProperty("data");
364
- });
365
-
366
- it("generates nested data with references", async () => {
367
- const plugin = fakerPlugin({
368
- schema: {
369
- $defs: {
370
- timestamp: { type: "string", format: "date-time" },
371
- user: {
372
- type: "object",
373
- properties: {
374
- id: { type: "string", format: "uuid" },
375
- name: { type: "string" },
376
- },
377
- },
378
- },
379
- type: "object",
380
- properties: {
381
- created: { $ref: "#/$defs/timestamp" },
382
- updated: { $ref: "#/$defs/timestamp" },
383
- author: { $ref: "#/$defs/user" },
384
- editor: { $ref: "#/$defs/user" },
385
- },
386
- },
387
- });
388
-
389
- const result = await plugin.process({
390
- method: "GET",
391
- path: "/api/document",
392
- params: {},
393
- query: {},
394
- state: {},
395
- headers: {},
396
- body: null,
397
- route: {},
398
- });
399
-
400
- expect(
401
- validators.appearsToBeFromCategory([result.response.created], "date"),
402
- ).toBe(true);
403
- expect(
404
- validators.appearsToBeFromCategory([result.response.updated], "date"),
405
- ).toBe(true);
406
- // $ref-resolved schemas may not preserve format through JSF resolution
407
- expect(result.response.author).toHaveProperty("id");
408
- expect(typeof result.response.author.id).toBe("string");
409
- expect(result.response.editor).toHaveProperty("id");
410
- expect(typeof result.response.editor.id).toBe("string");
411
- });
412
- });
413
-
414
- describe("Performance Characteristics", () => {
415
- it("maintains consistent performance across multiple calls", async () => {
416
- const plugin = fakerPlugin({
417
- schema: schemas.complex.user(),
418
- });
419
-
420
- const context = {
421
- method: "GET",
422
- path: "/api/user",
423
- params: {},
424
- query: {},
425
- state: {},
426
- headers: {},
427
- body: null,
428
- route: {},
429
- };
430
-
431
- // Generate multiple times
432
- const results: any[] = [];
433
- for (let i = 0; i < 10; i++) {
434
- const r = await plugin.process(context);
435
- results.push(r.response);
436
- }
437
-
438
- // All should be valid but different
439
- results.forEach((result) => {
440
- expect(result).toHaveProperty("id");
441
- expect(result).toHaveProperty("email");
442
- });
443
-
444
- // Should generate different data each time
445
- const emails = results.map((r) => r.email);
446
- const uniqueEmails = new Set(emails);
447
- expect(uniqueEmails.size).toBeGreaterThan(5);
448
- });
449
-
450
- it("handles large schemas efficiently", async () => {
451
- const plugin = fakerPlugin({
452
- schema: {
453
- type: "object",
454
- properties: Object.fromEntries(
455
- Array.from({ length: 50 }, (_, i) => [
456
- `field${i}`,
457
- { type: i % 2 === 0 ? "string" : "number" },
458
- ]),
459
- ),
460
- },
461
- });
462
-
463
- const context = {
464
- method: "GET",
465
- path: "/api/data",
466
- params: {},
467
- query: {},
468
- state: {},
469
- headers: {},
470
- body: null,
471
- route: {},
472
- };
473
-
474
- const result = await plugin.process(context);
475
-
476
- // Should have all fields
477
- expect(Object.keys(result.response).length).toBeGreaterThanOrEqual(50);
478
- });
479
- });
480
-
481
- describe("Real-world Plugin Usage", () => {
482
- it("generates mock API responses for testing", async () => {
483
- const plugin = fakerPlugin({
484
- schema: {
485
- type: "object",
486
- properties: {
487
- success: { type: "boolean", const: true },
488
- data: {
489
- type: "object",
490
- properties: {
491
- id: { type: "string", format: "uuid" },
492
- email: { type: "string", format: "email" },
493
- profile: {
494
- type: "object",
495
- properties: {
496
- name: { type: "string" },
497
- avatar: { type: "string", format: "uri" },
498
- },
499
- },
500
- },
501
- },
502
- timestamp: { type: "string", format: "date-time" },
503
- },
504
- },
505
- overrides: {
506
- "data.id": "{{params.userId}}",
507
- timestamp: "{{state.currentTime}}",
508
- },
509
- });
510
-
511
- const result = await plugin.process({
512
- method: "GET",
513
- path: "/api/users/user-123",
514
- params: { userId: "user-123" },
515
- query: {},
516
- state: new Map(),
517
- routeState: { currentTime: "2024-01-01T12:00:00Z" },
518
- headers: {},
519
- body: null,
520
- route: {},
521
- });
522
-
523
- expect(result.response.success).toBe(true);
524
- expect(result.response.data.id).toBe("user-123");
525
- expect(result.response.timestamp).toBe("2024-01-01T12:00:00Z");
526
- expect(
527
- validators.appearsToBeFromCategory(
528
- [result.response.data.email],
529
- "email",
530
- ),
531
- ).toBe(true);
532
- });
533
-
534
- it("works with schmock plugin pipeline", async () => {
535
- const schemaPlug = fakerPlugin({
536
- schema: schemas.simple.object({
537
- message: { type: "string" },
538
- code: { type: "number" },
539
- }),
540
- });
541
-
542
- // Mock another plugin in the pipeline
543
- const loggingPlugin = {
544
- name: "logger",
545
- version: "1.0.0",
546
- process: (ctx: any, response: any) => {
547
- console.log(`Processing ${ctx.path}`);
548
- return { context: ctx, response };
549
- },
550
- };
551
-
552
- // Simulate pipeline execution
553
- const context = {
554
- method: "GET",
555
- path: "/api/status",
556
- params: {},
557
- query: {},
558
- state: {},
559
- headers: {},
560
- body: null,
561
- route: {},
562
- };
563
-
564
- // First plugin generates response
565
- const result1 = await schemaPlug.process(context);
566
-
567
- // Second plugin receives generated response
568
- const result2 = loggingPlugin.process(result1.context, result1.response);
569
-
570
- expect(result2.response).toHaveProperty("message");
571
- expect(result2.response).toHaveProperty("code");
572
- expect(result2.response).toBe(result1.response); // Same reference
573
- });
574
- });
575
- });