@schmock/faker 2.2.3 → 2.3.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/dist/field-mappings.d.ts.map +1 -1
- package/dist/field-mappings.js +8 -1
- package/dist/field-name-matcher.d.ts.map +1 -1
- package/dist/field-name-matcher.js +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/jsf-config.d.ts +11 -1
- package/dist/jsf-config.d.ts.map +1 -1
- package/dist/jsf-config.js +93 -11
- package/dist/overrides.d.ts.map +1 -1
- package/dist/overrides.js +20 -14
- package/dist/schema-enhancement.d.ts.map +1 -1
- package/dist/schema-enhancement.js +18 -3
- package/dist/test-utils.d.ts +9 -9
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +25 -12
- package/dist/validation.js +1 -1
- package/package.json +4 -4
- package/src/field-mappings.ts +8 -1
- package/src/field-name-matcher.ts +4 -5
- package/src/index.test.ts +102 -0
- package/src/index.ts +59 -42
- package/src/jsf-config.test.ts +65 -0
- package/src/jsf-config.ts +129 -21
- package/src/overrides.ts +23 -20
- package/src/performance.test.ts +274 -327
- package/src/post-process.test.ts +87 -61
- package/src/schema-enhancement.test.ts +8 -2
- package/src/schema-enhancement.ts +24 -8
- package/src/steps/deterministic-seeds.steps.ts +77 -0
- package/src/steps/faker-plugin.steps.ts +198 -6
- package/src/test-utils.ts +48 -28
- package/src/validation.ts +1 -1
package/src/post-process.test.ts
CHANGED
|
@@ -8,80 +8,106 @@ import { generateFromSchema } from "./index";
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
describe("postProcessGenerated — schmockNullable", () => {
|
|
11
|
-
it("
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// postProcessGenerated with the schmockNullable flag.
|
|
23
|
-
|
|
24
|
-
// Direct approach: construct a schema that includes schmockNullable at the property level
|
|
25
|
-
const schema: JSONSchema7 & Record<string, unknown> = {
|
|
26
|
-
type: "object",
|
|
27
|
-
properties: {
|
|
28
|
-
value: {
|
|
29
|
-
type: "string",
|
|
30
|
-
schmockNullable: true,
|
|
31
|
-
} as JSONSchema7 & { schmockNullable: boolean },
|
|
11
|
+
it("uses the generation seed for a reproducible nullable distribution", async () => {
|
|
12
|
+
const nullableString: JSONSchema7 & { schmockNullable: boolean } = {
|
|
13
|
+
type: "string",
|
|
14
|
+
schmockNullable: true,
|
|
15
|
+
};
|
|
16
|
+
const schema: JSONSchema7 = {
|
|
17
|
+
type: "array",
|
|
18
|
+
items: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: { value: nullableString },
|
|
21
|
+
required: ["value"],
|
|
32
22
|
},
|
|
33
|
-
required: ["value"],
|
|
34
23
|
};
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
for (let i = 0; i < runs; i++) {
|
|
39
|
-
const result = (await generateFromSchema({ schema })) as Record<
|
|
40
|
-
string,
|
|
41
|
-
unknown
|
|
42
|
-
>;
|
|
43
|
-
if (result.value === null) {
|
|
44
|
-
nullCount++;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
25
|
+
const first = await generateFromSchema({ schema, count: 200, seed: 42 });
|
|
26
|
+
const second = await generateFromSchema({ schema, count: 200, seed: 42 });
|
|
47
27
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
28
|
+
expect(first).toEqual(second);
|
|
29
|
+
if (!Array.isArray(first)) {
|
|
30
|
+
throw new Error("Expected generated nullable data to be an array");
|
|
31
|
+
}
|
|
32
|
+
const values = first.map((item) => {
|
|
33
|
+
if (typeof item !== "object" || item === null || !("value" in item)) {
|
|
34
|
+
throw new Error("Expected each nullable item to contain value");
|
|
35
|
+
}
|
|
36
|
+
return item.value;
|
|
37
|
+
});
|
|
38
|
+
expect(values.filter((value) => value === null)).toHaveLength(9);
|
|
39
|
+
expect(values.filter((value) => typeof value === "string")).toHaveLength(
|
|
40
|
+
191,
|
|
41
|
+
);
|
|
53
42
|
});
|
|
54
43
|
});
|
|
55
44
|
|
|
56
45
|
describe("postProcessGenerated — schmockTrueProbability", () => {
|
|
57
|
-
it("
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
46
|
+
it("uses the generation seed for deterministic weighted booleans", async () => {
|
|
47
|
+
const weightedBoolean: JSONSchema7 & {
|
|
48
|
+
schmockTrueProbability: number;
|
|
49
|
+
} = {
|
|
50
|
+
type: "boolean",
|
|
51
|
+
schmockTrueProbability: 0.5,
|
|
52
|
+
};
|
|
53
|
+
const schema: JSONSchema7 = {
|
|
54
|
+
type: "array",
|
|
55
|
+
items: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: { flag: weightedBoolean },
|
|
58
|
+
required: ["flag"],
|
|
65
59
|
},
|
|
66
|
-
required: ["isActive"],
|
|
67
60
|
};
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (result.isActive === true) {
|
|
77
|
-
trueCount++;
|
|
78
|
-
}
|
|
62
|
+
const first = await generateFromSchema({ schema, count: 12, seed: 42 });
|
|
63
|
+
const second = await generateFromSchema({ schema, count: 12, seed: 42 });
|
|
64
|
+
|
|
65
|
+
expect(first).toEqual(second);
|
|
66
|
+
expect(Array.isArray(first)).toBe(true);
|
|
67
|
+
if (!Array.isArray(first)) {
|
|
68
|
+
throw new Error("Expected generated data to be an array");
|
|
79
69
|
}
|
|
70
|
+
const flags = first.flatMap((item) => {
|
|
71
|
+
if (typeof item !== "object" || item === null || !("flag" in item)) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return [item.flag];
|
|
75
|
+
});
|
|
76
|
+
expect(flags).toContain(true);
|
|
77
|
+
expect(flags).toContain(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("applies a reproducible weighted boolean distribution", async () => {
|
|
81
|
+
const weightedBoolean: JSONSchema7 & {
|
|
82
|
+
schmockTrueProbability: number;
|
|
83
|
+
} = {
|
|
84
|
+
type: "boolean",
|
|
85
|
+
schmockTrueProbability: 0.8,
|
|
86
|
+
};
|
|
87
|
+
const schema: JSONSchema7 = {
|
|
88
|
+
type: "array",
|
|
89
|
+
items: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: { flag: weightedBoolean },
|
|
92
|
+
required: ["flag"],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const first = await generateFromSchema({ schema, count: 200, seed: 42 });
|
|
97
|
+
const second = await generateFromSchema({ schema, count: 200, seed: 42 });
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
expect(first).toEqual(second);
|
|
100
|
+
if (!Array.isArray(first)) {
|
|
101
|
+
throw new Error("Expected generated weighted data to be an array");
|
|
102
|
+
}
|
|
103
|
+
const flags = first.map((item) => {
|
|
104
|
+
if (typeof item !== "object" || item === null || !("flag" in item)) {
|
|
105
|
+
throw new Error("Expected each weighted item to contain flag");
|
|
106
|
+
}
|
|
107
|
+
return item.flag;
|
|
108
|
+
});
|
|
109
|
+
expect(flags.filter((flag) => flag === true)).toHaveLength(162);
|
|
110
|
+
expect(flags.filter((flag) => flag === false)).toHaveLength(38);
|
|
85
111
|
});
|
|
86
112
|
});
|
|
87
113
|
|
|
@@ -170,10 +170,16 @@ describe("enhanceSchemaWithSmartMapping", () => {
|
|
|
170
170
|
expect(props.email.faker).toBe("lorem.word");
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
-
it("
|
|
173
|
+
it("adds useful text generation to an unconstrained root string", () => {
|
|
174
174
|
const schema: JSONSchema7 = { type: "string" };
|
|
175
175
|
const enhanced = enhanceSchemaWithSmartMapping(schema);
|
|
176
|
-
expect(enhanced).toEqual({ type: "string" });
|
|
176
|
+
expect(enhanced).toEqual({ type: "string", faker: "lorem.word" });
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("preserves an explicit zero minimum length", () => {
|
|
180
|
+
const schema: JSONSchema7 = { type: "string", minLength: 0 };
|
|
181
|
+
const enhanced = enhanceSchemaWithSmartMapping(schema);
|
|
182
|
+
expect(enhanced).toEqual(schema);
|
|
177
183
|
});
|
|
178
184
|
|
|
179
185
|
it("handles null/undefined schema gracefully", () => {
|
|
@@ -9,6 +9,20 @@ interface FakerSchema extends JSONSchema7 {
|
|
|
9
9
|
schmockTrueProbability?: number;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function needsStringFallback(schema: FakerSchema): boolean {
|
|
13
|
+
return (
|
|
14
|
+
schema.type === "string" &&
|
|
15
|
+
schema.faker === undefined &&
|
|
16
|
+
schema.format === undefined &&
|
|
17
|
+
schema.pattern === undefined &&
|
|
18
|
+
schema.enum === undefined &&
|
|
19
|
+
schema.const === undefined &&
|
|
20
|
+
schema.$ref === undefined &&
|
|
21
|
+
schema.minLength === undefined &&
|
|
22
|
+
schema.maxLength === undefined
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
export function enhanceSchemaWithSmartMapping(
|
|
13
27
|
schema: JSONSchema7,
|
|
14
28
|
): JSONSchema7 {
|
|
@@ -16,7 +30,7 @@ export function enhanceSchemaWithSmartMapping(
|
|
|
16
30
|
return schema;
|
|
17
31
|
}
|
|
18
32
|
|
|
19
|
-
const enhanced = { ...schema }
|
|
33
|
+
const enhanced: FakerSchema = { ...schema };
|
|
20
34
|
|
|
21
35
|
// Handle object properties
|
|
22
36
|
if (enhanced.properties) {
|
|
@@ -38,7 +52,7 @@ export function enhanceSchemaWithSmartMapping(
|
|
|
38
52
|
for (const keyword of ["allOf", "anyOf", "oneOf"] as const) {
|
|
39
53
|
const branches = enhanced[keyword];
|
|
40
54
|
if (Array.isArray(branches)) {
|
|
41
|
-
|
|
55
|
+
enhanced[keyword] = branches.map((branch) =>
|
|
42
56
|
isJSONSchema7(branch) ? enhanceSchemaWithSmartMapping(branch) : branch,
|
|
43
57
|
);
|
|
44
58
|
}
|
|
@@ -56,16 +70,16 @@ export function enhanceSchemaWithSmartMapping(
|
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
// Recurse into additionalProperties
|
|
59
|
-
if (
|
|
60
|
-
enhanced.additionalProperties &&
|
|
61
|
-
typeof enhanced.additionalProperties === "object" &&
|
|
62
|
-
!Array.isArray(enhanced.additionalProperties)
|
|
63
|
-
) {
|
|
73
|
+
if (isJSONSchema7(enhanced.additionalProperties)) {
|
|
64
74
|
enhanced.additionalProperties = enhanceSchemaWithSmartMapping(
|
|
65
|
-
enhanced.additionalProperties
|
|
75
|
+
enhanced.additionalProperties,
|
|
66
76
|
);
|
|
67
77
|
}
|
|
68
78
|
|
|
79
|
+
if (needsStringFallback(enhanced)) {
|
|
80
|
+
enhanced.faker = "lorem.word";
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
return enhanced;
|
|
70
84
|
}
|
|
71
85
|
|
|
@@ -122,6 +136,8 @@ function enhanceFieldSchema(
|
|
|
122
136
|
if (trueProbability !== undefined) {
|
|
123
137
|
enhanced.schmockTrueProbability = trueProbability;
|
|
124
138
|
}
|
|
139
|
+
} else if (needsStringFallback(enhanced)) {
|
|
140
|
+
enhanced.faker = "lorem.word";
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
return enhanced;
|
|
@@ -16,6 +16,10 @@ const testSchema = {
|
|
|
16
16
|
describeFeature(feature, ({ Scenario }) => {
|
|
17
17
|
let result1: unknown;
|
|
18
18
|
let result2: unknown;
|
|
19
|
+
let seededArray1: unknown;
|
|
20
|
+
let seededArray2: unknown;
|
|
21
|
+
let differentSeedResult1: unknown;
|
|
22
|
+
let differentSeedResult2: unknown;
|
|
19
23
|
|
|
20
24
|
Scenario("Same seed produces same output", ({ Given, When, Then }) => {
|
|
21
25
|
Given("a schema plugin with seed 42", () => {
|
|
@@ -32,4 +36,77 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
32
36
|
});
|
|
33
37
|
});
|
|
34
38
|
|
|
39
|
+
Scenario(
|
|
40
|
+
"Different seeds produce different output",
|
|
41
|
+
({ Given, When, Then }) => {
|
|
42
|
+
let firstSeed = 0;
|
|
43
|
+
let secondSeed = 0;
|
|
44
|
+
|
|
45
|
+
Given(
|
|
46
|
+
"a schema plugin using seeds {int} and {int}",
|
|
47
|
+
(_, seedA: number, seedB: number) => {
|
|
48
|
+
firstSeed = seedA;
|
|
49
|
+
secondSeed = seedB;
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
When("I generate data once with each seed", async () => {
|
|
54
|
+
differentSeedResult1 = await generateFromSchema({
|
|
55
|
+
schema: testSchema,
|
|
56
|
+
seed: firstSeed,
|
|
57
|
+
});
|
|
58
|
+
differentSeedResult2 = await generateFromSchema({
|
|
59
|
+
schema: testSchema,
|
|
60
|
+
seed: secondSeed,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
Then("the differently seeded outputs are distinct", () => {
|
|
65
|
+
expect(differentSeedResult1).not.toEqual(differentSeedResult2);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
Scenario(
|
|
71
|
+
"Seeded arrays are reproducible without repeating every item",
|
|
72
|
+
({ Given, When, Then, And }) => {
|
|
73
|
+
let count = 0;
|
|
74
|
+
|
|
75
|
+
Given(
|
|
76
|
+
"an array schema plugin with seed 42 and count {int}",
|
|
77
|
+
(_, requestedCount: number) => {
|
|
78
|
+
count = requestedCount;
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
When("I generate the seeded array twice", async () => {
|
|
83
|
+
const schema = {
|
|
84
|
+
type: "array" as const,
|
|
85
|
+
items: {
|
|
86
|
+
type: "object" as const,
|
|
87
|
+
properties: {
|
|
88
|
+
id: { type: "integer" as const },
|
|
89
|
+
name: { type: "string" as const },
|
|
90
|
+
},
|
|
91
|
+
required: ["id", "name"],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
seededArray1 = await generateFromSchema({ schema, count, seed: 42 });
|
|
95
|
+
seededArray2 = await generateFromSchema({ schema, count, seed: 42 });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
Then("both seeded arrays are identical", () => {
|
|
99
|
+
expect(seededArray1).toEqual(seededArray2);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
And("the seeded array contains varied items", () => {
|
|
103
|
+
expect(Array.isArray(seededArray1)).toBe(true);
|
|
104
|
+
if (!Array.isArray(seededArray1)) {
|
|
105
|
+
throw new Error("Expected seeded output to be an array");
|
|
106
|
+
}
|
|
107
|
+
const serialized = seededArray1.map((item) => JSON.stringify(item));
|
|
108
|
+
expect(new Set(serialized).size).toBeGreaterThan(1);
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
);
|
|
35
112
|
});
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
2
2
|
import { expect } from "vitest";
|
|
3
3
|
import { generateFromSchema } from "../index";
|
|
4
|
+
import { isJSONSchema7 } from "../validation";
|
|
4
5
|
|
|
5
6
|
const feature = await loadFeature("../../features/faker-plugin.feature");
|
|
6
7
|
|
|
7
8
|
describeFeature(feature, ({ Scenario }) => {
|
|
8
|
-
let generated:
|
|
9
|
+
let generated: unknown;
|
|
10
|
+
|
|
11
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isUnknownArray(value: unknown): value is unknown[] {
|
|
16
|
+
return Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseSchema(
|
|
20
|
+
docString: string,
|
|
21
|
+
): Schmock.SchemaGenerationContext["schema"] {
|
|
22
|
+
const parsed: unknown = JSON.parse(docString);
|
|
23
|
+
if (!isJSONSchema7(parsed)) {
|
|
24
|
+
throw new Error("Expected feature DocString to contain a JSON Schema");
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
9
28
|
|
|
10
29
|
Scenario(
|
|
11
30
|
"Generate object from simple schema",
|
|
12
31
|
({ Given, When, Then, And }) => {
|
|
13
|
-
let schema:
|
|
32
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
14
33
|
|
|
15
34
|
Given("I create a schema plugin with:", (_, docString: string) => {
|
|
16
|
-
schema =
|
|
35
|
+
schema = parseSchema(docString);
|
|
17
36
|
});
|
|
18
37
|
|
|
19
38
|
When("I generate data from the schema", async () => {
|
|
@@ -23,6 +42,9 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
23
42
|
Then(
|
|
24
43
|
"the generated data should have property {string} of type {string}",
|
|
25
44
|
(_, prop: string, type: string) => {
|
|
45
|
+
if (!isRecord(generated)) {
|
|
46
|
+
throw new Error("Expected generated data to be an object");
|
|
47
|
+
}
|
|
26
48
|
expect(generated).toHaveProperty(prop);
|
|
27
49
|
expect(typeof generated[prop]).toBe(type);
|
|
28
50
|
},
|
|
@@ -31,6 +53,9 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
31
53
|
And(
|
|
32
54
|
"the generated data should have property {string} of type {string}",
|
|
33
55
|
(_, prop: string, type: string) => {
|
|
56
|
+
if (!isRecord(generated)) {
|
|
57
|
+
throw new Error("Expected generated data to be an object");
|
|
58
|
+
}
|
|
34
59
|
expect(generated).toHaveProperty(prop);
|
|
35
60
|
expect(typeof generated[prop]).toBe(type);
|
|
36
61
|
},
|
|
@@ -41,13 +66,13 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
41
66
|
Scenario(
|
|
42
67
|
"Generate array of items with explicit count",
|
|
43
68
|
({ Given, When, Then }) => {
|
|
44
|
-
let schema:
|
|
69
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
45
70
|
let count: number;
|
|
46
71
|
|
|
47
72
|
Given(
|
|
48
73
|
"I create a schema plugin for array with count {int}:",
|
|
49
74
|
(_, cnt: number, docString: string) => {
|
|
50
|
-
schema =
|
|
75
|
+
schema = parseSchema(docString);
|
|
51
76
|
count = cnt;
|
|
52
77
|
},
|
|
53
78
|
);
|
|
@@ -70,7 +95,7 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
70
95
|
"Template preserves string values for mixed templates",
|
|
71
96
|
({ Given, When, Then }) => {
|
|
72
97
|
let template: string;
|
|
73
|
-
let result:
|
|
98
|
+
let result: unknown;
|
|
74
99
|
|
|
75
100
|
Given(
|
|
76
101
|
"I create a schema plugin with template override {string}",
|
|
@@ -99,6 +124,9 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
99
124
|
Then(
|
|
100
125
|
"the template result should be the string {string}",
|
|
101
126
|
(_, expected: string) => {
|
|
127
|
+
if (!isRecord(result)) {
|
|
128
|
+
throw new Error("Expected generated data to be an object");
|
|
129
|
+
}
|
|
102
130
|
expect(result.value).toBe(expected);
|
|
103
131
|
expect(typeof result.value).toBe("string");
|
|
104
132
|
},
|
|
@@ -106,4 +134,168 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
106
134
|
},
|
|
107
135
|
);
|
|
108
136
|
|
|
137
|
+
Scenario(
|
|
138
|
+
"Generate tuple positions from their respective schemas",
|
|
139
|
+
({ Given, When, Then }) => {
|
|
140
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
141
|
+
|
|
142
|
+
Given(
|
|
143
|
+
"I create a tuple schema with string, integer, and boolean positions",
|
|
144
|
+
() => {
|
|
145
|
+
schema = {
|
|
146
|
+
type: "array",
|
|
147
|
+
items: [
|
|
148
|
+
{ type: "string" },
|
|
149
|
+
{ type: "integer" },
|
|
150
|
+
{ type: "boolean" },
|
|
151
|
+
],
|
|
152
|
+
minItems: 3,
|
|
153
|
+
maxItems: 3,
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
When("I generate data from the schema", async () => {
|
|
159
|
+
generated = await generateFromSchema({ schema, seed: 42 });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
Then(
|
|
163
|
+
"the generated tuple should contain string, number, and boolean values in order",
|
|
164
|
+
() => {
|
|
165
|
+
if (!isUnknownArray(generated)) {
|
|
166
|
+
throw new Error("Expected generated tuple data to be an array");
|
|
167
|
+
}
|
|
168
|
+
expect(generated).toHaveLength(3);
|
|
169
|
+
expect(typeof generated[0]).toBe("string");
|
|
170
|
+
expect(typeof generated[1]).toBe("number");
|
|
171
|
+
expect(typeof generated[2]).toBe("boolean");
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
Scenario(
|
|
178
|
+
"Generate a nested tuple through a schema reference",
|
|
179
|
+
({ Given, When, Then }) => {
|
|
180
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
181
|
+
|
|
182
|
+
Given(
|
|
183
|
+
"I create an object schema whose payload references a tuple definition",
|
|
184
|
+
() => {
|
|
185
|
+
schema = {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
payload: { $ref: "#/definitions/payloadTuple" },
|
|
189
|
+
},
|
|
190
|
+
required: ["payload"],
|
|
191
|
+
definitions: {
|
|
192
|
+
payloadTuple: {
|
|
193
|
+
type: "array",
|
|
194
|
+
items: [
|
|
195
|
+
{ type: "string" },
|
|
196
|
+
{ type: "integer" },
|
|
197
|
+
{ type: "boolean" },
|
|
198
|
+
],
|
|
199
|
+
minItems: 3,
|
|
200
|
+
maxItems: 3,
|
|
201
|
+
additionalItems: false,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
When("I generate data from the schema", async () => {
|
|
209
|
+
generated = await generateFromSchema({ schema, seed: 42 });
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
Then(
|
|
213
|
+
"the generated payload tuple should contain string, number, and boolean values in order",
|
|
214
|
+
() => {
|
|
215
|
+
if (!isRecord(generated) || !Array.isArray(generated.payload)) {
|
|
216
|
+
throw new Error("Expected generated payload to be a tuple");
|
|
217
|
+
}
|
|
218
|
+
expect(generated.payload).toHaveLength(3);
|
|
219
|
+
expect(typeof generated.payload[0]).toBe("string");
|
|
220
|
+
expect(typeof generated.payload[1]).toBe("number");
|
|
221
|
+
expect(typeof generated.payload[2]).toBe("boolean");
|
|
222
|
+
},
|
|
223
|
+
);
|
|
224
|
+
},
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
Scenario(
|
|
228
|
+
"Apply overrides to every generated array item",
|
|
229
|
+
({ Given, When, Then }) => {
|
|
230
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
231
|
+
let count = 0;
|
|
232
|
+
let name = "";
|
|
233
|
+
|
|
234
|
+
Given(
|
|
235
|
+
"I create an object array schema with count {int} and override name {string}",
|
|
236
|
+
(_, requestedCount: number, overrideName: string) => {
|
|
237
|
+
count = requestedCount;
|
|
238
|
+
name = overrideName;
|
|
239
|
+
schema = {
|
|
240
|
+
type: "array",
|
|
241
|
+
items: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: { name: { type: "string" } },
|
|
244
|
+
required: ["name"],
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
When("I generate data from the schema", async () => {
|
|
251
|
+
generated = await generateFromSchema({
|
|
252
|
+
schema,
|
|
253
|
+
count,
|
|
254
|
+
overrides: { name },
|
|
255
|
+
seed: 42,
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
Then(
|
|
260
|
+
"every generated array item should have name {string}",
|
|
261
|
+
(_, expectedName: string) => {
|
|
262
|
+
if (!isUnknownArray(generated)) {
|
|
263
|
+
throw new Error(
|
|
264
|
+
"Expected generated collection data to be an array",
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
for (const item of generated) {
|
|
268
|
+
expect(item).toMatchObject({ name: expectedName });
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
},
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
Scenario(
|
|
276
|
+
"Generate useful text for an unconstrained string",
|
|
277
|
+
({ Given, When, Then }) => {
|
|
278
|
+
let schema: Schmock.SchemaGenerationContext["schema"];
|
|
279
|
+
|
|
280
|
+
Given("I create a schema plugin with:", (_, docString: string) => {
|
|
281
|
+
schema = parseSchema(docString);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
When("I generate data from the schema", async () => {
|
|
285
|
+
generated = await generateFromSchema({ schema, seed: 42 });
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
Then(
|
|
289
|
+
"the generated data should have a non-empty {string}",
|
|
290
|
+
(_, property: string) => {
|
|
291
|
+
if (!isRecord(generated)) {
|
|
292
|
+
throw new Error("Expected generated data to be an object");
|
|
293
|
+
}
|
|
294
|
+
const value = generated[property];
|
|
295
|
+
expect(typeof value).toBe("string");
|
|
296
|
+
expect(value).not.toBe("");
|
|
297
|
+
},
|
|
298
|
+
);
|
|
299
|
+
},
|
|
300
|
+
);
|
|
109
301
|
});
|