@schmock/core 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.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/abort.d.ts +3 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +30 -0
- package/dist/binary.d.ts +8 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +9 -0
- package/dist/builder.d.ts +31 -10
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +804 -203
- package/dist/constants.d.ts +38 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +123 -2
- package/dist/errors.d.ts +14 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +41 -6
- package/dist/helpers.d.ts +9 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +18 -2
- package/dist/http-helpers.d.ts +52 -5
- package/dist/http-helpers.d.ts.map +1 -1
- package/dist/http-helpers.js +153 -37
- package/dist/index.d.ts +381 -60
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/interceptor.d.ts +11 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +354 -156
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +12 -3
- package/dist/plugin-pipeline.d.ts +11 -4
- package/dist/plugin-pipeline.d.ts.map +1 -1
- package/dist/plugin-pipeline.js +117 -39
- package/dist/response-normalizer.d.ts +16 -0
- package/dist/response-normalizer.d.ts.map +1 -0
- package/dist/response-normalizer.js +316 -0
- package/dist/response-parser.d.ts.map +1 -1
- package/dist/response-parser.js +85 -18
- package/dist/route-matcher.d.ts +3 -0
- package/dist/route-matcher.d.ts.map +1 -1
- package/dist/route-matcher.js +12 -6
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +18 -8
- package/src/audit-core-builder.test.ts +0 -218
- package/src/audit-response-guard.test.ts +0 -38
- package/src/builder.test.ts +0 -289
- package/src/builder.ts +0 -701
- package/src/constants.test.ts +0 -99
- package/src/constants.ts +0 -73
- package/src/debug.test.ts +0 -241
- package/src/delay.test.ts +0 -319
- package/src/dist-shape.test.ts +0 -35
- package/src/errors.test.ts +0 -223
- package/src/errors.ts +0 -130
- package/src/factory.test.ts +0 -133
- package/src/helpers.test.ts +0 -147
- package/src/helpers.ts +0 -58
- package/src/http-helpers.ts +0 -113
- package/src/index.ts +0 -151
- package/src/interceptor.test.ts +0 -291
- package/src/interceptor.ts +0 -320
- package/src/namespace.test.ts +0 -274
- package/src/parser.property.test.ts +0 -594
- package/src/parser.test.ts +0 -148
- package/src/parser.ts +0 -64
- package/src/plugin-pipeline.ts +0 -103
- package/src/plugin-system.test.ts +0 -602
- package/src/response-parser.ts +0 -75
- package/src/response-parsing.test.ts +0 -333
- package/src/route-matcher.ts +0 -69
- package/src/route-matching.test.ts +0 -394
- package/src/server.test.ts +0 -165
- package/src/smart-defaults.test.ts +0 -361
- package/src/steps/async-support.steps.ts +0 -400
- package/src/steps/audit-core-builder.steps.ts +0 -188
- package/src/steps/audit-onerror-tuple.steps.ts +0 -99
- package/src/steps/basic-usage.steps.ts +0 -245
- package/src/steps/developer-experience.steps.ts +0 -204
- package/src/steps/error-handling.steps.ts +0 -345
- package/src/steps/fluent-api.steps.ts +0 -255
- package/src/steps/http-methods.steps.ts +0 -331
- package/src/steps/interceptor.steps.ts +0 -260
- package/src/steps/lifecycle-events.steps.ts +0 -142
- package/src/steps/performance-reliability.steps.ts +0 -423
- package/src/steps/plugin-integration.steps.ts +0 -280
- package/src/steps/request-history.steps.ts +0 -276
- package/src/steps/response-delay.steps.ts +0 -88
- package/src/steps/route-key-format.steps.ts +0 -99
- package/src/steps/standalone-server.steps.ts +0 -233
- package/src/steps/state-concurrency.steps.ts +0 -739
- package/src/steps/stateful-workflows.steps.ts +0 -353
- package/src/types.ts +0 -36
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
2
|
-
import { expect } from "vitest";
|
|
3
|
-
import type { CallableMockInstance } from "../types";
|
|
4
|
-
import { schmock } from "../index";
|
|
5
|
-
|
|
6
|
-
const feature = await loadFeature("../../features/basic-usage.feature");
|
|
7
|
-
|
|
8
|
-
describeFeature(feature, ({ Scenario }) => {
|
|
9
|
-
let mock: CallableMockInstance;
|
|
10
|
-
let response: any;
|
|
11
|
-
|
|
12
|
-
Scenario("Simplest possible mock - plain text", ({ Given, When, Then, And }) => {
|
|
13
|
-
Given("I create a plain text mock returning {string} at {string}", (_, text: string, route: string) => {
|
|
14
|
-
const [method, path] = route.split(" ");
|
|
15
|
-
mock = schmock();
|
|
16
|
-
mock(`${method} ${path}` as Schmock.RouteKey, text);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
When("I request {string}", async (_, request: string) => {
|
|
20
|
-
const [method, path] = request.split(" ");
|
|
21
|
-
response = await mock.handle(method as any, path);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
25
|
-
expect(response.body).toBe(expectedText);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
29
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
Scenario("Return JSON without specifying contentType", ({ Given, When, Then, And }) => {
|
|
34
|
-
Given("I create a mock returning a JSON array at {string}", (_, route: string) => {
|
|
35
|
-
const [method, path] = route.split(" ");
|
|
36
|
-
mock = schmock();
|
|
37
|
-
mock(`${method} ${path}` as Schmock.RouteKey, [{ id: 1, name: "John" }]);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
When("I request {string}", async (_, request: string) => {
|
|
41
|
-
const [method, path] = request.split(" ");
|
|
42
|
-
response = await mock.handle(method as any, path);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
Then("I should receive:", (_, docString: string) => {
|
|
46
|
-
const expected = JSON.parse(docString);
|
|
47
|
-
expect(response.body).toEqual(expected);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
51
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
Scenario("Return object without contentType", ({ Given, When, Then, And }) => {
|
|
56
|
-
Given("I create a mock returning a JSON object at {string}", (_, route: string) => {
|
|
57
|
-
const [method, path] = route.split(" ");
|
|
58
|
-
mock = schmock();
|
|
59
|
-
mock(`${method} ${path}` as Schmock.RouteKey, { id: 1, name: "John" });
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
When("I request {string}", async (_, request: string) => {
|
|
63
|
-
const [method, path] = request.split(" ");
|
|
64
|
-
response = await mock.handle(method as any, path);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
Then("I should receive:", (_, docString: string) => {
|
|
68
|
-
const expected = JSON.parse(docString);
|
|
69
|
-
expect(response.body).toEqual(expected);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
73
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
Scenario("Empty mock instance", ({ Given, When, Then }) => {
|
|
78
|
-
Given("I create an empty mock with no routes", () => {
|
|
79
|
-
mock = schmock();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
When("I request {string}", async (_, request: string) => {
|
|
83
|
-
const [method, path] = request.split(" ");
|
|
84
|
-
response = await mock.handle(method as any, path);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
Then("the status should be {int}", (_, status: number) => {
|
|
88
|
-
expect(response.status).toBe(status);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
Scenario("Null response", ({ Given, When, Then, And }) => {
|
|
93
|
-
Given("I create a mock returning null at {string}", (_, route: string) => {
|
|
94
|
-
const [method, path] = route.split(" ");
|
|
95
|
-
mock = schmock();
|
|
96
|
-
mock(`${method} ${path}` as Schmock.RouteKey, null);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
When("I request {string}", async (_, request: string) => {
|
|
100
|
-
const [method, path] = request.split(" ");
|
|
101
|
-
response = await mock.handle(method as any, path);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
Then("I should receive empty response", () => {
|
|
105
|
-
expect(response.body).toBeUndefined();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
And("the status should be {int}", (_, status: number) => {
|
|
109
|
-
expect(response.status).toBe(status);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
Scenario("Function returning string", ({ Given, When, Then }) => {
|
|
114
|
-
Given("I create a mock with a string generator at {string}", (_, route: string) => {
|
|
115
|
-
const [method, path] = route.split(" ");
|
|
116
|
-
mock = schmock();
|
|
117
|
-
mock(`${method} ${path}` as Schmock.RouteKey, () => "Dynamic response");
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
When("I request {string}", async (_, request: string) => {
|
|
121
|
-
const [method, path] = request.split(" ");
|
|
122
|
-
response = await mock.handle(method as any, path);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
126
|
-
expect(response.body).toBe(expectedText);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
Scenario("Function returning object", ({ Given, When, Then, And }) => {
|
|
131
|
-
Given("I create a mock with an object generator at {string}", (_, route: string) => {
|
|
132
|
-
const [method, path] = route.split(" ");
|
|
133
|
-
mock = schmock();
|
|
134
|
-
mock(`${method} ${path}` as Schmock.RouteKey, () => ({ timestamp: Date.now() }));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
When("I request {string}", async (_, request: string) => {
|
|
138
|
-
const [method, path] = request.split(" ");
|
|
139
|
-
response = await mock.handle(method as any, path);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
Then("the response should be valid JSON", () => {
|
|
143
|
-
expect(() => JSON.parse(JSON.stringify(response.body))).not.toThrow();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
And("the response should have property {string}", (_, property: string) => {
|
|
147
|
-
expect(response.body).toHaveProperty(property);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
Scenario("Multiple routes", ({ Given, When, Then, And }) => {
|
|
152
|
-
let homeResponse: any;
|
|
153
|
-
let aboutResponse: any;
|
|
154
|
-
let contactResponse: any;
|
|
155
|
-
|
|
156
|
-
Given("I create a mock with three routes", () => {
|
|
157
|
-
mock = schmock();
|
|
158
|
-
mock("GET /", "Home");
|
|
159
|
-
mock("GET /about", "About Us");
|
|
160
|
-
mock("GET /contact", { email: "test@example.com" });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
When("I make three requests to different routes", async () => {
|
|
164
|
-
homeResponse = await mock.handle("GET", "/");
|
|
165
|
-
aboutResponse = await mock.handle("GET", "/about");
|
|
166
|
-
contactResponse = await mock.handle("GET", "/contact");
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
Then("the home route should return {string}", (_, expectedText: string) => {
|
|
170
|
-
expect(homeResponse.body).toBe(expectedText);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
And("the about route should return {string}", (_, expectedText: string) => {
|
|
174
|
-
expect(aboutResponse.body).toBe(expectedText);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
And("the contact route should return:", (_, docString: string) => {
|
|
178
|
-
const expected = JSON.parse(docString);
|
|
179
|
-
expect(contactResponse.body).toEqual(expected);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
Scenario("Override contentType detection", ({ Given, When, Then, And }) => {
|
|
184
|
-
Given("I create a mock with explicit text/plain contentType at {string}", (_, route: string) => {
|
|
185
|
-
const [method, path] = route.split(" ");
|
|
186
|
-
mock = schmock();
|
|
187
|
-
mock(`${method} ${path}` as Schmock.RouteKey, { foo: "bar" }, { contentType: "text/plain" });
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
When("I request {string}", async (_, request: string) => {
|
|
191
|
-
const [method, path] = request.split(" ");
|
|
192
|
-
response = await mock.handle(method as any, path);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
196
|
-
expect(response.body).toBe(expectedText);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
200
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
Scenario("HTML response", ({ Given, When, Then, And }) => {
|
|
205
|
-
Given("I create a mock returning HTML at {string}", (_, route: string) => {
|
|
206
|
-
const [method, path] = route.split(" ");
|
|
207
|
-
mock = schmock();
|
|
208
|
-
mock(`${method} ${path}` as Schmock.RouteKey, "<h1>Hello</h1>", { contentType: "text/html" });
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
When("I request {string}", async (_, request: string) => {
|
|
212
|
-
const [method, path] = request.split(" ");
|
|
213
|
-
response = await mock.handle(method as any, path);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
217
|
-
expect(response.body).toBe(expectedText);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
221
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
Scenario("Binary/buffer response detection", ({ Given, When, Then, And }) => {
|
|
226
|
-
Given("I create a mock returning a Buffer at {string}", (_, route: string) => {
|
|
227
|
-
const [method, path] = route.split(" ");
|
|
228
|
-
mock = schmock();
|
|
229
|
-
mock(`${method} ${path}` as Schmock.RouteKey, Buffer.from("binary data") as unknown as Schmock.Generator);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
When("I request {string}", async (_, request: string) => {
|
|
233
|
-
const [method, path] = request.split(" ");
|
|
234
|
-
response = await mock.handle(method as any, path);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
Then("I should receive buffer data", () => {
|
|
238
|
-
expect(Buffer.isBuffer(response.body)).toBe(true);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
242
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
});
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
2
|
-
import { expect } from "vitest";
|
|
3
|
-
import { schmock } from "../index";
|
|
4
|
-
import type { CallableMockInstance, Plugin, PluginContext } from "../types";
|
|
5
|
-
|
|
6
|
-
const feature = await loadFeature("../../features/developer-experience.feature");
|
|
7
|
-
|
|
8
|
-
describeFeature(feature, ({ Scenario }) => {
|
|
9
|
-
let mock: CallableMockInstance;
|
|
10
|
-
let response: any;
|
|
11
|
-
let responses: any[] = [];
|
|
12
|
-
|
|
13
|
-
Scenario("State confusion between global and local state", ({ Given, When, Then, And }) => {
|
|
14
|
-
Given("I create a mock with global state and a local state counter", () => {
|
|
15
|
-
mock = schmock({ state: { global: 1 } });
|
|
16
|
-
mock("GET /counter", ({ state }) => {
|
|
17
|
-
const current = (state.local as number | undefined) || 0;
|
|
18
|
-
state.local = current + 1;
|
|
19
|
-
return { global: state.global, local: state.local };
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
When("I request {string} twice", async (_, request: string) => {
|
|
24
|
-
const [method, path] = request.split(" ");
|
|
25
|
-
responses = [];
|
|
26
|
-
responses.push(await mock.handle(method as any, path));
|
|
27
|
-
responses.push(await mock.handle(method as any, path));
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
Then("the first response should have:", (_, docString: string) => {
|
|
31
|
-
const expected = JSON.parse(docString);
|
|
32
|
-
expect(responses[0].body).toEqual(expected);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
And("the second response should have:", (_, docString: string) => {
|
|
36
|
-
const expected = JSON.parse(docString);
|
|
37
|
-
expect(responses[1].body).toEqual(expected);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
Scenario("Route precedence with similar paths", ({ Given, When, Then, And }) => {
|
|
42
|
-
Given("I create a mock with an exact route and a parameterized route on {string}", (_, basePath: string) => {
|
|
43
|
-
mock = schmock();
|
|
44
|
-
mock(`GET ${basePath}/profile`, { type: "profile" });
|
|
45
|
-
mock(`GET ${basePath}/:id`, ({ params }) => ({ type: "user", id: params.id }));
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
When("I test both route precedence scenarios", async () => {
|
|
49
|
-
responses = [];
|
|
50
|
-
responses.push(await mock.handle("GET", "/users/profile"));
|
|
51
|
-
responses.push(await mock.handle("GET", "/users/123"));
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
Then("the profile route should return exact match:", (_, docString: string) => {
|
|
55
|
-
const expected = JSON.parse(docString);
|
|
56
|
-
expect(responses[0].body).toEqual(expected);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
And("the parameterized route should match with param:", (_, docString: string) => {
|
|
60
|
-
const expected = JSON.parse(docString);
|
|
61
|
-
expect(responses[1].body).toEqual(expected);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
Scenario("Plugin order affecting results", ({ Given, When, Then }) => {
|
|
66
|
-
Given("I create a mock with two plugins that each set a step number", () => {
|
|
67
|
-
mock = schmock();
|
|
68
|
-
const plugin1: Plugin = {
|
|
69
|
-
name: "first",
|
|
70
|
-
process: (ctx: PluginContext, response: unknown) => ({
|
|
71
|
-
context: ctx,
|
|
72
|
-
response: { ...(response as Record<string, unknown>), step: 1 },
|
|
73
|
-
}),
|
|
74
|
-
};
|
|
75
|
-
const plugin2: Plugin = {
|
|
76
|
-
name: "second",
|
|
77
|
-
process: (ctx: PluginContext, response: unknown) => ({
|
|
78
|
-
context: ctx,
|
|
79
|
-
response: { ...(response as Record<string, unknown>), step: 2 },
|
|
80
|
-
}),
|
|
81
|
-
};
|
|
82
|
-
mock("GET /order", { original: true }).pipe(plugin1).pipe(plugin2);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
When("I request {string}", async (_, request: string) => {
|
|
86
|
-
const [method, path] = request.split(" ");
|
|
87
|
-
response = await mock.handle(method as any, path);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
Then("I should receive:", (_, docString: string) => {
|
|
91
|
-
const expected = JSON.parse(docString);
|
|
92
|
-
expect(response.body).toEqual(expected);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
Scenario("Plugin expecting different context structure", ({ Given, When, Then }) => {
|
|
97
|
-
Given("I create a mock with a plugin that reads context properties", () => {
|
|
98
|
-
mock = schmock();
|
|
99
|
-
const plugin: Plugin = {
|
|
100
|
-
name: "context-reader",
|
|
101
|
-
process: (ctx: PluginContext, _response: unknown) => ({
|
|
102
|
-
context: ctx,
|
|
103
|
-
response: {
|
|
104
|
-
method: ctx.method,
|
|
105
|
-
path: ctx.path,
|
|
106
|
-
hasBody: !!ctx.body,
|
|
107
|
-
hasQuery: !!ctx.query && Object.keys(ctx.query).length > 0,
|
|
108
|
-
},
|
|
109
|
-
}),
|
|
110
|
-
};
|
|
111
|
-
mock("POST /analyze", null).pipe(plugin);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
When("I request {string} with body:", async (_, request: string, docString: string) => {
|
|
115
|
-
const [method, fullPath] = request.split(" ");
|
|
116
|
-
const [path, queryString] = fullPath.split("?");
|
|
117
|
-
|
|
118
|
-
const query: Record<string, string> = {};
|
|
119
|
-
if (queryString) {
|
|
120
|
-
queryString.split("&").forEach((param) => {
|
|
121
|
-
const [key, value] = param.split("=");
|
|
122
|
-
query[key] = value || "";
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const body = JSON.parse(docString);
|
|
127
|
-
response = await mock.handle(method as any, path, { body, query });
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
Then("I should receive:", (_, docString: string) => {
|
|
131
|
-
const expected = JSON.parse(docString);
|
|
132
|
-
expect(response.body).toEqual(expected);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
Scenario("Response tuple format edge cases", ({ Given, When, Then, And }) => {
|
|
137
|
-
Given("I create a mock with three tuple response routes", () => {
|
|
138
|
-
mock = schmock();
|
|
139
|
-
mock("GET /created", [201, null]);
|
|
140
|
-
mock("GET /with-headers", [200, { data: true }, { "x-custom": "header" }]);
|
|
141
|
-
mock("GET /empty-with-status", [204, null]);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
When("I test all tuple response formats", async () => {
|
|
145
|
-
responses = [];
|
|
146
|
-
responses.push(await mock.handle("GET", "/created"));
|
|
147
|
-
responses.push(await mock.handle("GET", "/with-headers"));
|
|
148
|
-
responses.push(await mock.handle("GET", "/empty-with-status"));
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
Then("the created endpoint should return status 201 with empty body", () => {
|
|
152
|
-
expect(responses[0].status).toBe(201);
|
|
153
|
-
expect(responses[0].body).toBeUndefined();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
And("the headers endpoint should return status 200 with data and custom header", () => {
|
|
157
|
-
expect(responses[1].status).toBe(200);
|
|
158
|
-
expect(responses[1].body).toEqual({ data: true });
|
|
159
|
-
expect(responses[1].headers?.["x-custom"]).toBe("header");
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
And("the empty endpoint should return status 204 with null body", () => {
|
|
163
|
-
expect(responses[2].status).toBe(204);
|
|
164
|
-
expect(responses[2].body).toBeUndefined();
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
Scenario("Registering duplicate routes first route wins", ({ Given, When, Then }) => {
|
|
169
|
-
Given("I create a mock with two routes on {string} with different data", (_, route: string) => {
|
|
170
|
-
mock = schmock();
|
|
171
|
-
mock(route as Schmock.RouteKey, [{ id: 1 }]);
|
|
172
|
-
mock(route as Schmock.RouteKey, [{ id: 2 }]);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
When("I request {string}", async (_, request: string) => {
|
|
176
|
-
const [method, path] = request.split(" ");
|
|
177
|
-
response = await mock.handle(method as any, path);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
Then("the first route response should win:", (_, docString: string) => {
|
|
181
|
-
const expected = JSON.parse(docString);
|
|
182
|
-
expect(response.body).toEqual(expected);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
Scenario("Duplicate routes are not duplicated in getRoutes()", ({ Given, When, Then }) => {
|
|
187
|
-
let routesList: ReturnType<typeof mock.getRoutes>;
|
|
188
|
-
|
|
189
|
-
Given("I create a mock with two routes on {string} with different data", (_, route: string) => {
|
|
190
|
-
mock = schmock();
|
|
191
|
-
mock(route as Schmock.RouteKey, [{ id: 1 }]);
|
|
192
|
-
mock(route as Schmock.RouteKey, [{ id: 2 }]);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
When("I call getRoutes", () => {
|
|
196
|
-
routesList = mock.getRoutes();
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
Then("only one route entry is returned", () => {
|
|
200
|
-
expect(routesList).toHaveLength(1);
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
});
|