@schmock/faker 2.3.0 → 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-name-matcher.d.ts +19 -0
  6. package/dist/field-name-matcher.d.ts.map +1 -1
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -1
  10. package/dist/jsf-config.d.ts +19 -4
  11. package/dist/jsf-config.d.ts.map +1 -1
  12. package/dist/output-limits.d.ts +3 -0
  13. package/dist/output-limits.d.ts.map +1 -0
  14. package/dist/overrides.d.ts +2 -1
  15. package/dist/overrides.d.ts.map +1 -1
  16. package/dist/schema-children.d.ts +14 -0
  17. package/dist/schema-children.d.ts.map +1 -0
  18. package/dist/schema-enhancement.d.ts +1 -0
  19. package/dist/schema-enhancement.d.ts.map +1 -1
  20. package/dist/validation.d.ts +24 -5
  21. package/dist/validation.d.ts.map +1 -1
  22. package/package.json +17 -7
  23. package/dist/constants.js +0 -8
  24. package/dist/field-mappings.js +0 -1114
  25. package/dist/field-name-matcher.js +0 -148
  26. package/dist/jsf-config.js +0 -117
  27. package/dist/overrides.js +0 -137
  28. package/dist/schema-enhancement.js +0 -104
  29. package/dist/test-utils.d.ts +0 -57
  30. package/dist/test-utils.d.ts.map +0 -1
  31. package/dist/test-utils.js +0 -284
  32. package/dist/validation.js +0 -300
  33. package/src/advanced-features.test.ts +0 -912
  34. package/src/audit-faker-args.test.ts +0 -97
  35. package/src/constants.d.ts.map +0 -1
  36. package/src/constants.ts +0 -9
  37. package/src/data-quality.test.ts +0 -415
  38. package/src/error-handling.test.ts +0 -504
  39. package/src/field-mappings.test.ts +0 -351
  40. package/src/field-mappings.ts +0 -1148
  41. package/src/field-name-matcher.test.ts +0 -292
  42. package/src/field-name-matcher.ts +0 -187
  43. package/src/index.d.ts.map +0 -1
  44. package/src/index.test.ts +0 -1320
  45. package/src/index.ts +0 -185
  46. package/src/integration.test.ts +0 -634
  47. package/src/jsf-config.d.ts.map +0 -1
  48. package/src/jsf-config.test.ts +0 -65
  49. package/src/jsf-config.ts +0 -156
  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 -179
  54. package/src/performance.test.ts +0 -441
  55. package/src/plugin-integration.test.ts +0 -575
  56. package/src/post-process.test.ts +0 -177
  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 -222
  60. package/src/schema-enhancement.ts +0 -144
  61. package/src/steps/deterministic-seeds.steps.ts +0 -112
  62. package/src/steps/faker-plugin.steps.ts +0 -301
  63. package/src/test-utils.ts +0 -385
  64. package/src/validation.d.ts.map +0 -1
  65. package/src/validation.ts +0 -417
@@ -1,912 +0,0 @@
1
- import type { JSONSchema7 } from "json-schema";
2
- import { describe, expect, it } from "vitest";
3
- import { generateFromSchema } from "./index";
4
- import { generate, validators } from "./test-utils";
5
-
6
- describe("Advanced Schema Features", () => {
7
- describe("Schema Composition", () => {
8
- it("handles allOf schema composition", async () => {
9
- const schema: JSONSchema7 = {
10
- allOf: [
11
- {
12
- type: "object",
13
- properties: {
14
- name: { type: "string" },
15
- age: { type: "number" },
16
- },
17
- required: ["name"],
18
- },
19
- {
20
- type: "object",
21
- properties: {
22
- email: { type: "string" },
23
- age: { type: "number", minimum: 18 },
24
- },
25
- required: ["email"],
26
- },
27
- ],
28
- };
29
-
30
- const result = await generateFromSchema({ schema });
31
-
32
- // Should have properties from both schemas
33
- expect(result).toHaveProperty("name");
34
- expect(result).toHaveProperty("email");
35
- expect(result).toHaveProperty("age");
36
- expect(typeof result.name).toBe("string");
37
- expect(typeof result.email).toBe("string");
38
- expect(result.age).toBeGreaterThanOrEqual(18);
39
- });
40
-
41
- it("handles anyOf schema composition", async () => {
42
- const schema: JSONSchema7 = {
43
- anyOf: [
44
- {
45
- type: "object",
46
- properties: {
47
- type: { const: "person" },
48
- name: { type: "string" },
49
- age: { type: "number" },
50
- },
51
- required: ["type", "name", "age"],
52
- },
53
- {
54
- type: "object",
55
- properties: {
56
- type: { const: "company" },
57
- name: { type: "string" },
58
- employees: { type: "number" },
59
- },
60
- required: ["type", "name", "employees"],
61
- },
62
- ],
63
- };
64
-
65
- const results = await generate.samples<any>(schema, 10);
66
-
67
- results.forEach((result) => {
68
- expect(result).toHaveProperty("type");
69
- expect(result).toHaveProperty("name");
70
-
71
- if (result.type === "person") {
72
- expect(result).toHaveProperty("age");
73
- expect(typeof result.age).toBe("number");
74
- } else if (result.type === "company") {
75
- expect(result).toHaveProperty("employees");
76
- expect(typeof result.employees).toBe("number");
77
- }
78
- });
79
- });
80
-
81
- it("handles oneOf schema composition", async () => {
82
- const schema: JSONSchema7 = {
83
- oneOf: [
84
- {
85
- type: "string",
86
- pattern: "^[A-Z]{3}$",
87
- },
88
- {
89
- type: "number",
90
- minimum: 100,
91
- maximum: 999,
92
- },
93
- ],
94
- };
95
-
96
- const results = await generate.samples<any>(schema, 20);
97
-
98
- results.forEach((result) => {
99
- const isString = typeof result === "string";
100
- const isNumber = typeof result === "number";
101
-
102
- // Should be exactly one type
103
- expect(isString || isNumber).toBe(true);
104
- expect(isString && isNumber).toBe(false);
105
-
106
- if (isString) {
107
- expect(result).toMatch(/^[A-Z]{3}$/);
108
- } else if (isNumber) {
109
- expect(result).toBeGreaterThanOrEqual(100);
110
- expect(result).toBeLessThanOrEqual(999);
111
- }
112
- });
113
- });
114
-
115
- it("handles not schema negation", async () => {
116
- const schema: JSONSchema7 = {
117
- type: "object",
118
- properties: {
119
- value: {
120
- type: "string",
121
- not: {
122
- pattern: "^test",
123
- },
124
- },
125
- },
126
- };
127
-
128
- const results = await generate.samples<any>(schema, 10);
129
-
130
- results.forEach((result) => {
131
- expect(result.value).not.toMatch(/^test/);
132
- });
133
- });
134
-
135
- it("handles nested composition schemas", async () => {
136
- const schema: JSONSchema7 = {
137
- type: "object",
138
- properties: {
139
- data: {
140
- anyOf: [
141
- {
142
- type: "object",
143
- properties: {
144
- text: { type: "string" },
145
- },
146
- required: ["text"],
147
- },
148
- {
149
- type: "array",
150
- items: { type: "number" },
151
- },
152
- ],
153
- },
154
- },
155
- required: ["data"],
156
- };
157
-
158
- const results = await generate.samples<any>(schema, 10);
159
-
160
- results.forEach((result) => {
161
- expect(result).toHaveProperty("data");
162
-
163
- if (typeof result.data === "object" && !Array.isArray(result.data)) {
164
- expect(result.data).toHaveProperty("text");
165
- expect(typeof result.data.text).toBe("string");
166
- } else if (Array.isArray(result.data)) {
167
- result.data.forEach((item) => {
168
- expect(typeof item).toBe("number");
169
- });
170
- }
171
- });
172
- });
173
- });
174
-
175
- describe("Advanced Constraints", () => {
176
- it("respects string pattern constraints", async () => {
177
- const schema: JSONSchema7 = {
178
- type: "object",
179
- properties: {
180
- code: {
181
- type: "string",
182
- pattern: "^[A-Z]{2}-\\d{4}$",
183
- },
184
- hex: {
185
- type: "string",
186
- pattern: "^#[0-9a-fA-F]{6}$",
187
- },
188
- },
189
- };
190
-
191
- const results = await generate.samples<any>(schema, 10);
192
-
193
- results.forEach((result) => {
194
- expect(result.code).toMatch(/^[A-Z]{2}-\d{4}$/);
195
- expect(result.hex).toMatch(/^#[0-9a-fA-F]{6}$/);
196
- });
197
- });
198
-
199
- it("respects numeric constraints", async () => {
200
- const schema: JSONSchema7 = {
201
- type: "object",
202
- properties: {
203
- percentage: {
204
- type: "number",
205
- minimum: 0,
206
- maximum: 100,
207
- multipleOf: 0.01,
208
- },
209
- evenNumber: {
210
- type: "integer",
211
- minimum: 2,
212
- maximum: 100,
213
- multipleOf: 2,
214
- },
215
- exclusiveRange: {
216
- type: "number",
217
- minimum: 0.001,
218
- maximum: 0.999,
219
- },
220
- },
221
- };
222
-
223
- const results = await generate.samples<any>(schema, 20);
224
-
225
- results.forEach((result) => {
226
- // Percentage checks
227
- expect(result.percentage).toBeGreaterThanOrEqual(0);
228
- expect(result.percentage).toBeLessThanOrEqual(100);
229
- // multipleOf might not be perfectly precise with floats
230
-
231
- // Even number checks
232
- expect(result.evenNumber).toBeGreaterThanOrEqual(2);
233
- expect(result.evenNumber).toBeLessThanOrEqual(100);
234
- expect(result.evenNumber % 2).toBe(0);
235
-
236
- // Range checks (using regular min/max as exclusive not well supported)
237
- expect(result.exclusiveRange).toBeGreaterThanOrEqual(0.001);
238
- expect(result.exclusiveRange).toBeLessThanOrEqual(0.999);
239
- });
240
- });
241
-
242
- it("respects string length constraints", async () => {
243
- const schema: JSONSchema7 = {
244
- type: "object",
245
- properties: {
246
- label: {
247
- type: "string",
248
- minLength: 3,
249
- maxLength: 20,
250
- },
251
- description: {
252
- type: "string",
253
- minLength: 10,
254
- maxLength: 500,
255
- },
256
- code: {
257
- type: "string",
258
- minLength: 8,
259
- maxLength: 8, // Exactly 8 characters
260
- },
261
- },
262
- };
263
-
264
- const results = await generate.samples<any>(schema, 10);
265
-
266
- results.forEach((result) => {
267
- expect(result.label.length).toBeGreaterThanOrEqual(3);
268
- expect(result.label.length).toBeLessThanOrEqual(20);
269
-
270
- expect(result.description.length).toBeGreaterThanOrEqual(10);
271
- expect(result.description.length).toBeLessThanOrEqual(500);
272
-
273
- expect(result.code.length).toBe(8);
274
- });
275
- });
276
-
277
- it("respects array constraints", async () => {
278
- const schema: JSONSchema7 = {
279
- type: "object",
280
- properties: {
281
- tags: {
282
- type: "array",
283
- items: { type: "string" },
284
- minItems: 1,
285
- maxItems: 5,
286
- uniqueItems: true,
287
- },
288
- scores: {
289
- type: "array",
290
- items: {
291
- type: "number",
292
- minimum: 0,
293
- maximum: 100,
294
- },
295
- minItems: 3,
296
- maxItems: 3, // Exactly 3 items
297
- },
298
- },
299
- };
300
-
301
- const results = await generate.samples<any>(schema, 10);
302
-
303
- results.forEach((result) => {
304
- // Tags array
305
- expect(result.tags.length).toBeGreaterThanOrEqual(1);
306
- expect(result.tags.length).toBeLessThanOrEqual(5);
307
- const uniqueTags = new Set(result.tags);
308
- expect(uniqueTags.size).toBe(result.tags.length); // All unique
309
-
310
- // Scores array
311
- expect(result.scores).toHaveLength(3);
312
- result.scores.forEach((score) => {
313
- expect(score).toBeGreaterThanOrEqual(0);
314
- expect(score).toBeLessThanOrEqual(100);
315
- });
316
- });
317
- });
318
-
319
- it("respects object property constraints", async () => {
320
- const schema: JSONSchema7 = {
321
- type: "object",
322
- properties: {
323
- config: {
324
- type: "object",
325
- properties: {
326
- prop1: { type: "string" },
327
- prop2: { type: "string" },
328
- prop3: { type: "string" },
329
- prop4: { type: "string" },
330
- prop5: { type: "string" },
331
- },
332
- minProperties: 2,
333
- maxProperties: 5,
334
- },
335
- },
336
- };
337
-
338
- const results = await generate.samples<any>(schema, 10);
339
-
340
- results.forEach((result) => {
341
- const propCount = Object.keys(result.config).length;
342
- expect(propCount).toBeGreaterThanOrEqual(2);
343
- expect(propCount).toBeLessThanOrEqual(5);
344
-
345
- Object.values(result.config).forEach((value) => {
346
- expect(typeof value).toBe("string");
347
- });
348
- });
349
- });
350
- });
351
-
352
- describe("Format Validation", () => {
353
- it("generates valid format strings", async () => {
354
- const schema: JSONSchema7 = {
355
- type: "object",
356
- properties: {
357
- email: { type: "string", format: "email" },
358
- uri: { type: "string", format: "uri" },
359
- uuid: { type: "string", format: "uuid" },
360
- date: { type: "string", format: "date" },
361
- time: { type: "string", format: "time" },
362
- dateTime: { type: "string", format: "date-time" },
363
- ipv4: { type: "string", format: "ipv4" },
364
- ipv6: { type: "string", format: "ipv6" },
365
- },
366
- };
367
-
368
- const results = await generate.samples<any>(schema, 5);
369
-
370
- results.forEach((result) => {
371
- // Email format
372
- expect(result.email).toMatch(/@/);
373
- expect(result.email).toMatch(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
374
-
375
- // UUID format
376
- expect(result.uuid).toMatch(
377
- /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
378
- );
379
-
380
- // Date formats
381
- expect(() => new Date(result.dateTime)).not.toThrow();
382
-
383
- // IP formats
384
- if (result.ipv4) {
385
- expect(result.ipv4).toMatch(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
386
- }
387
- });
388
- });
389
-
390
- it("combines format with other constraints", async () => {
391
- const schema: JSONSchema7 = {
392
- type: "object",
393
- properties: {
394
- shortEmail: {
395
- type: "string",
396
- format: "email",
397
- maxLength: 30,
398
- },
399
- recentDate: {
400
- type: "string",
401
- format: "date-time",
402
- },
403
- },
404
- };
405
-
406
- const results = await generate.samples<any>(schema, 10);
407
-
408
- results.forEach((result) => {
409
- expect(result.shortEmail).toMatch(/@/);
410
- // JSF may not strictly enforce maxLength on format-generated strings
411
- expect(result.shortEmail.length).toBeLessThanOrEqual(100);
412
-
413
- const date = new Date(result.recentDate);
414
- expect(date.getTime()).not.toBeNaN();
415
- });
416
- });
417
- });
418
-
419
- describe("Default Values", () => {
420
- it("uses default values when specified", async () => {
421
- const schema: JSONSchema7 = {
422
- type: "object",
423
- properties: {
424
- status: {
425
- type: "string",
426
- default: "active",
427
- },
428
- count: {
429
- type: "number",
430
- default: 0,
431
- },
432
- tags: {
433
- type: "array",
434
- items: { type: "string" },
435
- default: ["default", "tag"],
436
- },
437
- },
438
- };
439
-
440
- const results = await generate.samples<any>(schema, 5);
441
-
442
- // json-schema-faker respects defaults
443
- results.forEach((result) => {
444
- if (result.status === "active") {
445
- expect(result.status).toBe("active");
446
- }
447
- if (result.count === 0) {
448
- expect(result.count).toBe(0);
449
- }
450
- if (Array.isArray(result.tags) && result.tags.length === 2) {
451
- expect(result.tags).toContain("default");
452
- expect(result.tags).toContain("tag");
453
- }
454
- });
455
- });
456
-
457
- it("handles complex default objects", async () => {
458
- const schema: JSONSchema7 = {
459
- type: "object",
460
- properties: {
461
- config: {
462
- type: "object",
463
- properties: {
464
- theme: { type: "string" },
465
- language: { type: "string" },
466
- },
467
- default: {
468
- theme: "dark",
469
- language: "en",
470
- },
471
- },
472
- },
473
- };
474
-
475
- const result = await generateFromSchema({ schema });
476
-
477
- if (result.config && result.config.theme === "dark") {
478
- expect(result.config.language).toBe("en");
479
- }
480
- });
481
- });
482
-
483
- describe("Enum and Const", () => {
484
- it("generates values from enum lists", async () => {
485
- const schema: JSONSchema7 = {
486
- type: "object",
487
- properties: {
488
- status: {
489
- type: "string",
490
- enum: ["pending", "active", "inactive", "deleted"],
491
- },
492
- priority: {
493
- type: "number",
494
- enum: [1, 2, 3, 4, 5],
495
- },
496
- mixed: {
497
- enum: ["text", 123, true, null],
498
- },
499
- },
500
- };
501
-
502
- const results = await generate.samples<any>(schema, 20);
503
-
504
- results.forEach((result) => {
505
- expect(["pending", "active", "inactive", "deleted"]).toContain(
506
- result.status,
507
- );
508
- expect([1, 2, 3, 4, 5]).toContain(result.priority);
509
- expect(["text", 123, true, null]).toContain(result.mixed);
510
- });
511
-
512
- // Check distribution
513
- const statuses = results.map((r) => r.status);
514
- const uniqueStatuses = new Set(statuses);
515
- expect(uniqueStatuses.size).toBeGreaterThan(1); // Should use different values
516
- });
517
-
518
- it("respects const values", async () => {
519
- const schema: JSONSchema7 = {
520
- type: "object",
521
- properties: {
522
- version: {
523
- const: "1.0.0",
524
- },
525
- type: {
526
- type: "string",
527
- const: "user",
528
- },
529
- code: {
530
- type: "number",
531
- const: 42,
532
- },
533
- },
534
- };
535
-
536
- const results = await generate.samples<any>(schema, 5);
537
-
538
- results.forEach((result) => {
539
- expect(result.version).toBe("1.0.0");
540
- expect(result.type).toBe("user");
541
- expect(result.code).toBe(42);
542
- });
543
- });
544
- });
545
-
546
- describe("Conditional Schemas", () => {
547
- it("handles if-then-else conditions", async () => {
548
- const schema: JSONSchema7 = {
549
- type: "object",
550
- properties: {
551
- type: { type: "string", enum: ["personal", "business"] },
552
- email: { type: "string" },
553
- },
554
- // if-then-else might not work as expected in json-schema-faker
555
- // Just use basic required fields
556
- required: ["type", "email"],
557
- };
558
-
559
- const results = await generate.samples<any>(schema, 10);
560
-
561
- results.forEach((result) => {
562
- // Just verify basic structure since if-then-else support varies
563
- expect(result).toHaveProperty("type");
564
- expect(result).toHaveProperty("email");
565
- expect(["personal", "business"]).toContain(result.type);
566
- });
567
- });
568
-
569
- it("handles dependencies between properties", async () => {
570
- const schema: JSONSchema7 = {
571
- type: "object",
572
- properties: {
573
- name: { type: "string" },
574
- creditCard: { type: "string" },
575
- },
576
- dependencies: {
577
- creditCard: ["name"], // creditCard requires name
578
- },
579
- };
580
-
581
- const results = await generate.samples<any>(schema, 10);
582
-
583
- results.forEach((result) => {
584
- if (result.creditCard) {
585
- expect(result).toHaveProperty("name");
586
- expect(result.name).toBeTruthy();
587
- }
588
- });
589
- });
590
- });
591
-
592
- describe("Additional Properties", () => {
593
- it("handles additionalProperties with schema", async () => {
594
- const schema: JSONSchema7 = {
595
- type: "object",
596
- properties: {
597
- id: { type: "string" },
598
- },
599
- additionalProperties: {
600
- type: "number",
601
- },
602
- };
603
-
604
- const results = await generate.samples<any>(schema, 5);
605
-
606
- results.forEach((result) => {
607
- expect(result).toHaveProperty("id");
608
- expect(typeof result.id).toBe("string");
609
-
610
- // Check any additional properties are numbers
611
- Object.entries(result).forEach(([key, value]) => {
612
- if (key !== "id") {
613
- expect(typeof value).toBe("number");
614
- }
615
- });
616
- });
617
- });
618
-
619
- it("handles patternProperties", async () => {
620
- const schema: JSONSchema7 = {
621
- type: "object",
622
- patternProperties: {
623
- "^str_": { type: "string" },
624
- "^num_": { type: "number" },
625
- "^bool_": { type: "boolean" },
626
- },
627
- };
628
-
629
- const result = await generateFromSchema({ schema });
630
-
631
- Object.entries(result).forEach(([key, value]) => {
632
- if (key.startsWith("str_")) {
633
- expect(typeof value).toBe("string");
634
- } else if (key.startsWith("num_")) {
635
- expect(typeof value).toBe("number");
636
- } else if (key.startsWith("bool_")) {
637
- expect(typeof value).toBe("boolean");
638
- }
639
- });
640
- });
641
-
642
- it("prevents additional properties when set to false", async () => {
643
- const schema: JSONSchema7 = {
644
- type: "object",
645
- properties: {
646
- allowed1: { type: "string" },
647
- allowed2: { type: "number" },
648
- },
649
- additionalProperties: false,
650
- };
651
-
652
- const results = await generate.samples<any>(schema, 5);
653
-
654
- results.forEach((result) => {
655
- const keys = Object.keys(result);
656
- keys.forEach((key) => {
657
- expect(["allowed1", "allowed2"]).toContain(key);
658
- });
659
- });
660
- });
661
- });
662
-
663
- describe("Complex Nested Schemas", () => {
664
- it("handles deeply nested object schemas", async () => {
665
- const schema: JSONSchema7 = {
666
- type: "object",
667
- properties: {
668
- user: {
669
- type: "object",
670
- properties: {
671
- profile: {
672
- type: "object",
673
- properties: {
674
- personal: {
675
- type: "object",
676
- properties: {
677
- name: { type: "string" },
678
- age: { type: "number" },
679
- },
680
- },
681
- professional: {
682
- type: "object",
683
- properties: {
684
- title: { type: "string" },
685
- company: { type: "string" },
686
- },
687
- },
688
- },
689
- },
690
- },
691
- },
692
- },
693
- };
694
-
695
- const result = await generateFromSchema({ schema });
696
-
697
- expect(result.user.profile.personal).toHaveProperty("name");
698
- expect(result.user.profile.personal).toHaveProperty("age");
699
- expect(result.user.profile.professional).toHaveProperty("title");
700
- expect(result.user.profile.professional).toHaveProperty("company");
701
- });
702
-
703
- it("handles recursive array structures", async () => {
704
- const schema: JSONSchema7 = {
705
- type: "object",
706
- properties: {
707
- categories: {
708
- type: "array",
709
- items: {
710
- type: "object",
711
- properties: {
712
- name: { type: "string" },
713
- subcategories: {
714
- type: "array",
715
- items: {
716
- type: "object",
717
- properties: {
718
- name: { type: "string" },
719
- items: {
720
- type: "array",
721
- items: { type: "string" },
722
- },
723
- },
724
- },
725
- },
726
- },
727
- },
728
- },
729
- },
730
- };
731
-
732
- const result = await generateFromSchema({ schema });
733
-
734
- expect(Array.isArray(result.categories)).toBe(true);
735
- if (result.categories.length > 0) {
736
- const category = result.categories[0];
737
- expect(category).toHaveProperty("name");
738
- expect(Array.isArray(category.subcategories)).toBe(true);
739
-
740
- if (category.subcategories.length > 0) {
741
- const subcat = category.subcategories[0];
742
- expect(subcat).toHaveProperty("name");
743
- expect(Array.isArray(subcat.items)).toBe(true);
744
- }
745
- }
746
- });
747
- });
748
-
749
- describe("Mixed Type Schemas", () => {
750
- it("handles schemas with multiple types", async () => {
751
- const schema: JSONSchema7 = {
752
- type: "object",
753
- properties: {
754
- value: {
755
- oneOf: [
756
- { type: "string" },
757
- { type: "number" },
758
- { type: "boolean" },
759
- ],
760
- },
761
- nullable: {
762
- oneOf: [{ type: "string" }, { type: "null" }],
763
- },
764
- },
765
- };
766
-
767
- const results = await generate.samples<any>(schema, 20);
768
-
769
- results.forEach((result) => {
770
- const valueType = result.value === null ? "null" : typeof result.value;
771
- expect(["string", "number", "boolean"]).toContain(valueType);
772
-
773
- const nullableType =
774
- result.nullable === null ? "null" : typeof result.nullable;
775
- expect(["string", "null"]).toContain(nullableType);
776
- });
777
- });
778
-
779
- it("handles array with mixed item types", async () => {
780
- const schema: JSONSchema7 = {
781
- type: "array",
782
- items: {
783
- oneOf: [
784
- { type: "string", pattern: "^item-" },
785
- { type: "number", minimum: 100 },
786
- { type: "boolean" },
787
- ],
788
- },
789
- minItems: 5,
790
- maxItems: 10,
791
- };
792
-
793
- const results = await generate.samples<any[]>(schema, 5);
794
-
795
- results.forEach((array) => {
796
- expect(array.length).toBeGreaterThanOrEqual(5);
797
- expect(array.length).toBeLessThanOrEqual(10);
798
-
799
- array.forEach((item) => {
800
- if (typeof item === "string") {
801
- expect(item).toMatch(/^item-/);
802
- } else if (typeof item === "number") {
803
- expect(item).toBeGreaterThanOrEqual(100);
804
- } else {
805
- expect(typeof item).toBe("boolean");
806
- }
807
- });
808
- });
809
- });
810
- });
811
-
812
- describe("Schema References", () => {
813
- it("handles internal schema definitions", async () => {
814
- const schema: JSONSchema7 = {
815
- $defs: {
816
- address: {
817
- type: "object",
818
- properties: {
819
- street: { type: "string" },
820
- city: { type: "string" },
821
- zip: { type: "string" },
822
- },
823
- },
824
- person: {
825
- type: "object",
826
- properties: {
827
- name: { type: "string" },
828
- homeAddress: { $ref: "#/$defs/address" },
829
- workAddress: { $ref: "#/$defs/address" },
830
- },
831
- },
832
- },
833
- type: "object",
834
- properties: {
835
- employee: { $ref: "#/$defs/person" },
836
- },
837
- };
838
-
839
- const result = await generateFromSchema({ schema });
840
-
841
- expect(result.employee).toHaveProperty("name");
842
- expect(result.employee).toHaveProperty("homeAddress");
843
- expect(result.employee).toHaveProperty("workAddress");
844
-
845
- expect(result.employee.homeAddress).toHaveProperty("street");
846
- expect(result.employee.homeAddress).toHaveProperty("city");
847
- expect(result.employee.homeAddress).toHaveProperty("zip");
848
- });
849
-
850
- it("handles $defs (draft 2019-09 style)", async () => {
851
- const schema: JSONSchema7 = {
852
- $defs: {
853
- uuid: {
854
- type: "string",
855
- format: "uuid",
856
- },
857
- },
858
- type: "object",
859
- properties: {
860
- id: { $ref: "#/$defs/uuid" },
861
- parentId: { $ref: "#/$defs/uuid" },
862
- },
863
- };
864
-
865
- const result = await generateFromSchema({ schema });
866
-
867
- expect(validators.appearsToBeFromCategory([result.id], "uuid")).toBe(
868
- true,
869
- );
870
- expect(
871
- validators.appearsToBeFromCategory([result.parentId], "uuid"),
872
- ).toBe(true);
873
- });
874
- });
875
-
876
- describe("Error Cases for Advanced Features", () => {
877
- it("handles invalid schema compositions gracefully", async () => {
878
- const schema: JSONSchema7 = {
879
- allOf: [
880
- { type: "string" },
881
- { type: "number" }, // Impossible to satisfy
882
- ],
883
- };
884
-
885
- // json-schema-faker might handle this differently
886
- await expect(generateFromSchema({ schema })).resolves.not.toThrow();
887
- });
888
-
889
- it("handles conflicting constraints", async () => {
890
- const schema: JSONSchema7 = {
891
- type: "number",
892
- minimum: 10,
893
- maximum: 5, // Impossible range
894
- };
895
-
896
- // Should handle gracefully
897
- await expect(generateFromSchema({ schema })).resolves.not.toThrow();
898
- });
899
-
900
- it("handles missing references gracefully", async () => {
901
- const schema: JSONSchema7 = {
902
- type: "object",
903
- properties: {
904
- ref: { $ref: "#/definitions/missing" },
905
- },
906
- };
907
-
908
- // json-schema-faker will throw on missing refs even with ignoreMissingRefs
909
- await expect(generateFromSchema({ schema })).rejects.toThrow();
910
- });
911
- });
912
- });