@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,345 +0,0 @@
|
|
|
1
|
-
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
2
|
-
import { expect } from "vitest";
|
|
3
|
-
import type { CallableMockInstance, Plugin } from "../types";
|
|
4
|
-
import { schmock } from "../index";
|
|
5
|
-
|
|
6
|
-
const feature = await loadFeature("../../features/error-handling.feature");
|
|
7
|
-
|
|
8
|
-
describeFeature(feature, ({ Scenario }) => {
|
|
9
|
-
let mock: CallableMockInstance;
|
|
10
|
-
let response: any;
|
|
11
|
-
|
|
12
|
-
Scenario("Route not found returns 404", ({ Given, When, Then, And }) => {
|
|
13
|
-
Given("I create a mock with a GET /users route returning a user list", () => {
|
|
14
|
-
mock = schmock();
|
|
15
|
-
mock("GET /users", [{ id: 1, name: "John" }]);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
When("I request {string}", async (_, request: string) => {
|
|
19
|
-
const [method, path] = request.split(" ");
|
|
20
|
-
response = await mock.handle(method as any, path);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
24
|
-
expect(response.status).toBe(status);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
28
|
-
expect(response.body.error).toContain(errorMessage);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
And("the response should have error code {string}", (_, errorCode: string) => {
|
|
32
|
-
expect(response.body.code).toBe(errorCode);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
Scenario("Wrong HTTP method returns 404", ({ Given, When, Then, And }) => {
|
|
37
|
-
Given("I create a mock with a GET /api/data route returning success", () => {
|
|
38
|
-
mock = schmock();
|
|
39
|
-
mock("GET /api/data", { success: true });
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
When("I request {string}", async (_, request: string) => {
|
|
43
|
-
const [method, path] = request.split(" ");
|
|
44
|
-
response = await mock.handle(method as any, path);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
48
|
-
expect(response.status).toBe(status);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
52
|
-
expect(response.body.error).toContain(errorMessage);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
Scenario("Plugin throws error returns 500 with PluginError", ({ Given, When, Then, And }) => {
|
|
57
|
-
Given("I create a mock with a plugin that throws {string}", (_, errorMsg: string) => {
|
|
58
|
-
mock = schmock();
|
|
59
|
-
const failingPlugin: Plugin = {
|
|
60
|
-
name: "failing-plugin",
|
|
61
|
-
process: () => { throw new Error(errorMsg); },
|
|
62
|
-
};
|
|
63
|
-
mock("GET /test", "original").pipe(failingPlugin);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
When("I request {string}", async (_, request: string) => {
|
|
67
|
-
const [method, path] = request.split(" ");
|
|
68
|
-
response = await mock.handle(method as any, path);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
72
|
-
expect(response.status).toBe(status);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
76
|
-
expect(response.body.error).toContain(errorMessage);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
And("the response should have error code {string}", (_, errorCode: string) => {
|
|
80
|
-
expect(response.body.code).toBe(errorCode);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
Scenario("Plugin onError hook recovers from failure", ({ Given, When, Then, And }) => {
|
|
85
|
-
Given("I create a mock with a recoverable plugin that returns {string}", (_, recoveredBody: string) => {
|
|
86
|
-
mock = schmock();
|
|
87
|
-
const recoverablePlugin: Plugin = {
|
|
88
|
-
name: "recoverable",
|
|
89
|
-
process: () => { throw new Error("Initial failure"); },
|
|
90
|
-
onError: () => ({ status: 200, body: recoveredBody, headers: {} }),
|
|
91
|
-
};
|
|
92
|
-
mock("GET /test", "original").pipe(recoverablePlugin);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
When("I request {string}", async (_, request: string) => {
|
|
96
|
-
const [method, path] = request.split(" ");
|
|
97
|
-
response = await mock.handle(method as any, path);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
101
|
-
expect(response.status).toBe(status);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
And("I should receive text {string}", (_, expectedText: string) => {
|
|
105
|
-
expect(response.body).toBe(expectedText);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
Scenario("Plugin returns invalid result structure", ({ Given, When, Then, And }) => {
|
|
110
|
-
Given("I create a mock with a plugin returning an invalid result", () => {
|
|
111
|
-
mock = schmock();
|
|
112
|
-
const invalidPlugin: Plugin = {
|
|
113
|
-
name: "invalid",
|
|
114
|
-
process: () => ({ wrongStructure: true }) as any,
|
|
115
|
-
};
|
|
116
|
-
mock("GET /test", "original").pipe(invalidPlugin);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
When("I request {string}", async (_, request: string) => {
|
|
120
|
-
const [method, path] = request.split(" ");
|
|
121
|
-
response = await mock.handle(method as any, path);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
125
|
-
expect(response.status).toBe(status);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
129
|
-
expect(response.body.error).toContain(errorMessage);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
Scenario("Function generator throws error returns 500", ({ Given, When, Then, And }) => {
|
|
134
|
-
Given("I create a mock with a generator that throws {string}", (_, errorMsg: string) => {
|
|
135
|
-
mock = schmock();
|
|
136
|
-
mock("GET /fail", () => { throw new Error(errorMsg); });
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
When("I request {string}", async (_, request: string) => {
|
|
140
|
-
const [method, path] = request.split(" ");
|
|
141
|
-
response = await mock.handle(method as any, path);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
145
|
-
expect(response.status).toBe(status);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
149
|
-
expect(response.body.error).toContain(errorMessage);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
And("the response should have error code {string}", (_, errorCode: string) => {
|
|
153
|
-
expect(response.body.code).toBe(errorCode);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
Scenario("Namespace mismatch returns 404", ({ Given, When, Then, And }) => {
|
|
158
|
-
Given("I create a mock with namespace {string} and a GET /users route", (_, namespace: string) => {
|
|
159
|
-
mock = schmock({ namespace });
|
|
160
|
-
mock("GET /users", [{ id: 1 }]);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
When("I request {string}", async (_, request: string) => {
|
|
164
|
-
const [method, path] = request.split(" ");
|
|
165
|
-
response = await mock.handle(method as any, path);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
169
|
-
expect(response.status).toBe(status);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
173
|
-
expect(response.body.error).toContain(errorMessage);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
Scenario("Multiple plugin failures cascade properly", ({ Given, When, Then, And }) => {
|
|
178
|
-
Given("I create a mock with two failing plugins piped in sequence", () => {
|
|
179
|
-
mock = schmock();
|
|
180
|
-
const plugin1: Plugin = {
|
|
181
|
-
name: "first-fail",
|
|
182
|
-
process: () => { throw new Error("First error"); },
|
|
183
|
-
};
|
|
184
|
-
const plugin2: Plugin = {
|
|
185
|
-
name: "second-fail",
|
|
186
|
-
process: () => { throw new Error("Second error"); },
|
|
187
|
-
};
|
|
188
|
-
mock("GET /cascade", "original").pipe(plugin1).pipe(plugin2);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
When("I request {string}", async (_, request: string) => {
|
|
192
|
-
const [method, path] = request.split(" ");
|
|
193
|
-
response = await mock.handle(method as any, path);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
197
|
-
expect(response.status).toBe(status);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
201
|
-
expect(response.body.error).toContain(errorMessage);
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
Scenario("Plugin onError hook also fails", ({ Given, When, Then, And }) => {
|
|
206
|
-
Given("I create a mock with a plugin whose error handler also throws", () => {
|
|
207
|
-
mock = schmock({ debug: true });
|
|
208
|
-
const brokenPlugin: Plugin = {
|
|
209
|
-
name: "broken-handler",
|
|
210
|
-
process: () => { throw new Error("Process failed"); },
|
|
211
|
-
onError: () => { throw new Error("Handler failed"); },
|
|
212
|
-
};
|
|
213
|
-
mock("GET /broken", "original").pipe(brokenPlugin);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
When("I request {string}", async (_, request: string) => {
|
|
217
|
-
const [method, path] = request.split(" ");
|
|
218
|
-
response = await mock.handle(method as any, path);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
222
|
-
expect(response.status).toBe(status);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
226
|
-
expect(response.body.error).toContain(errorMessage);
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
Scenario("Empty parameter in route returns 404", ({ Given, When, Then, And }) => {
|
|
231
|
-
Given("I create a mock with a parameterized route {string}", (_, route: string) => {
|
|
232
|
-
mock = schmock();
|
|
233
|
-
mock(route as any, ({ params }: any) => ({ userId: params.id }));
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
When("I request {string}", async (_, request: string) => {
|
|
237
|
-
const [method, path] = request.split(" ");
|
|
238
|
-
response = await mock.handle(method as any, path);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
242
|
-
expect(response.status).toBe(status);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
246
|
-
expect(response.body.error).toContain(errorMessage);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
Scenario("Async generator error handling", ({ Given, When, Then, And }) => {
|
|
251
|
-
Given("I create a mock with an async generator that throws {string}", (_, errorMsg: string) => {
|
|
252
|
-
mock = schmock();
|
|
253
|
-
mock("GET /async-fail", async () => {
|
|
254
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
255
|
-
throw new Error(errorMsg);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
When("I request {string}", async (_, request: string) => {
|
|
260
|
-
const [method, path] = request.split(" ");
|
|
261
|
-
response = await mock.handle(method as any, path);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
265
|
-
expect(response.status).toBe(status);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
269
|
-
expect(response.body.error).toContain(errorMessage);
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
Scenario("Error responses include proper headers", ({ Given, When, Then, And }) => {
|
|
274
|
-
Given("I create a mock with a generator that throws {string}", (_, errorMsg: string) => {
|
|
275
|
-
mock = schmock();
|
|
276
|
-
mock("GET /error", () => { throw new Error(errorMsg); });
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
When("I request {string}", async (_, request: string) => {
|
|
280
|
-
const [method, path] = request.split(" ");
|
|
281
|
-
response = await mock.handle(method as any, path);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
285
|
-
expect(response.status).toBe(status);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
289
|
-
expect(response.headers).toBeDefined();
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
And("the response body should be valid JSON", () => {
|
|
293
|
-
expect(() => JSON.parse(JSON.stringify(response.body))).not.toThrow();
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
Scenario("Plugin onError returns response with status 0", ({ Given, When, Then, And }) => {
|
|
298
|
-
Given("I create a mock with a plugin whose error handler returns status 0", () => {
|
|
299
|
-
mock = schmock();
|
|
300
|
-
const plugin: Plugin = {
|
|
301
|
-
name: "zero-status",
|
|
302
|
-
process: () => { throw new Error("fail"); },
|
|
303
|
-
onError: () => ({ status: 0, body: "zero status", headers: {} }),
|
|
304
|
-
};
|
|
305
|
-
mock("GET /zero", "original").pipe(plugin);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
When("I request {string}", async (_, request: string) => {
|
|
309
|
-
const [method, path] = request.split(" ");
|
|
310
|
-
response = await mock.handle(method as any, path);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
314
|
-
expect(response.status).toBe(status);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
And("I should receive text {string}", (_, expectedText: string) => {
|
|
318
|
-
expect(response.body).toBe(expectedText);
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
Scenario("Plugin null/undefined return handling", ({ Given, When, Then, And }) => {
|
|
323
|
-
Given("I create a mock with a plugin that returns null", () => {
|
|
324
|
-
mock = schmock();
|
|
325
|
-
const nullPlugin: Plugin = {
|
|
326
|
-
name: "null-plugin",
|
|
327
|
-
process: () => null as any,
|
|
328
|
-
};
|
|
329
|
-
mock("GET /null", "original").pipe(nullPlugin);
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
When("I request {string}", async (_, request: string) => {
|
|
333
|
-
const [method, path] = request.split(" ");
|
|
334
|
-
response = await mock.handle(method as any, path);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
338
|
-
expect(response.status).toBe(status);
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
342
|
-
expect(response.body.error).toContain(errorMessage);
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
});
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
|
|
2
|
-
import { expect } from "vitest";
|
|
3
|
-
import { schmock } from "../index";
|
|
4
|
-
import type { CallableMockInstance } from "../types";
|
|
5
|
-
|
|
6
|
-
const feature = await loadFeature("../../features/fluent-api.feature");
|
|
7
|
-
|
|
8
|
-
describeFeature(feature, ({ Scenario }) => {
|
|
9
|
-
let mock: CallableMockInstance;
|
|
10
|
-
let response: any;
|
|
11
|
-
let responses: any[] = [];
|
|
12
|
-
|
|
13
|
-
Scenario("Simple route with generator function", ({ Given, When, Then }) => {
|
|
14
|
-
Given("I create a mock with a JSON generator at {string}", (_, route: string) => {
|
|
15
|
-
mock = schmock({});
|
|
16
|
-
mock(route as Schmock.RouteKey, () => [{ id: 1, name: "John" }], {
|
|
17
|
-
contentType: "application/json",
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
When("I request {string}", async (_, request: string) => {
|
|
22
|
-
const [method, path] = request.split(" ");
|
|
23
|
-
response = await mock.handle(method as any, path);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
Then("I should receive:", (_, docString: string) => {
|
|
27
|
-
const expected = JSON.parse(docString);
|
|
28
|
-
expect(response.body).toEqual(expected);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
Scenario(
|
|
33
|
-
"Route with dynamic response and global state",
|
|
34
|
-
({ Given, When, Then, And }) => {
|
|
35
|
-
responses = [];
|
|
36
|
-
|
|
37
|
-
Given("I create a mock with a stateful counter", () => {
|
|
38
|
-
mock = schmock({ state: { count: 0 } });
|
|
39
|
-
mock(
|
|
40
|
-
"GET /counter",
|
|
41
|
-
({ state }) => {
|
|
42
|
-
const s = state as { count: number };
|
|
43
|
-
s.count++;
|
|
44
|
-
return { value: s.count };
|
|
45
|
-
},
|
|
46
|
-
{ contentType: "application/json" },
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
When("I request {string} twice", async (_, request: string) => {
|
|
51
|
-
const [method, path] = request.split(" ");
|
|
52
|
-
responses = [];
|
|
53
|
-
responses.push(await mock.handle(method as any, path));
|
|
54
|
-
responses.push(await mock.handle(method as any, path));
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
Then("the first response should have value {int}", (_, value: number) => {
|
|
58
|
-
expect(responses[0].body).toEqual({ value });
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
And("the second response should have value {int}", (_, value: number) => {
|
|
62
|
-
expect(responses[1].body).toEqual({ value });
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
Scenario("Route with parameters", ({ Given, When, Then }) => {
|
|
68
|
-
Given("I create a mock with a parameterized route {string}", (_, route: string) => {
|
|
69
|
-
mock = schmock({});
|
|
70
|
-
mock(route as Schmock.RouteKey, ({ params }) => ({ userId: params.id }), {
|
|
71
|
-
contentType: "application/json",
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
When("I request {string}", async (_, request: string) => {
|
|
76
|
-
const [method, path] = request.split(" ");
|
|
77
|
-
response = await mock.handle(method as any, path);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
Then("I should receive:", (_, docString: string) => {
|
|
81
|
-
const expected = JSON.parse(docString);
|
|
82
|
-
expect(response.body).toEqual(expected);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
Scenario("Response with custom status code", ({ Given, When, Then, And }) => {
|
|
87
|
-
Given("I create a mock returning status {int} for {string}", (_, _status: number, route: string) => {
|
|
88
|
-
mock = schmock({});
|
|
89
|
-
mock(route as Schmock.RouteKey, ({ body }) => {
|
|
90
|
-
const b = body as Record<string, unknown>;
|
|
91
|
-
return [201, { id: 1, ...b }];
|
|
92
|
-
}, {
|
|
93
|
-
contentType: "application/json",
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
When(
|
|
98
|
-
"I request {string} with body:",
|
|
99
|
-
async (_, request: string, docString: string) => {
|
|
100
|
-
const [method, path] = request.split(" ");
|
|
101
|
-
const body = JSON.parse(docString);
|
|
102
|
-
response = await mock.handle(method as any, path, { body });
|
|
103
|
-
},
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
Then("the status should be {int}", (_, status: number) => {
|
|
107
|
-
expect(response.status).toBe(status);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
And("I should receive:", (_, docString: string) => {
|
|
111
|
-
const expected = JSON.parse(docString);
|
|
112
|
-
expect(response.body).toEqual(expected);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
Scenario("Static data response", ({ Given, When, Then }) => {
|
|
117
|
-
Given("I create a mock with static config data at {string}", (_, route: string) => {
|
|
118
|
-
mock = schmock({});
|
|
119
|
-
mock(route as Schmock.RouteKey, { version: "1.0.0", features: ["auth"] }, {
|
|
120
|
-
contentType: "application/json",
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
When("I request {string}", async (_, request: string) => {
|
|
125
|
-
const [method, path] = request.split(" ");
|
|
126
|
-
response = await mock.handle(method as any, path);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
Then("I should receive:", (_, docString: string) => {
|
|
130
|
-
const expected = JSON.parse(docString);
|
|
131
|
-
expect(response.body).toEqual(expected);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
Scenario("404 for undefined routes", ({ Given, When, Then }) => {
|
|
136
|
-
Given("I create a mock with only a {string} route", (_, route: string) => {
|
|
137
|
-
mock = schmock({});
|
|
138
|
-
mock(route as Schmock.RouteKey, () => [], { contentType: "application/json" });
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
When("I request {string}", async (_, request: string) => {
|
|
142
|
-
const [method, path] = request.split(" ");
|
|
143
|
-
response = await mock.handle(method as any, path);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
Then("the status should be {int}", (_, status: number) => {
|
|
147
|
-
expect(response.status).toBe(status);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
Scenario("Query parameters", ({ Given, When, Then }) => {
|
|
152
|
-
Given("I create a mock that reads query parameters at {string}", (_, route: string) => {
|
|
153
|
-
mock = schmock({});
|
|
154
|
-
mock(
|
|
155
|
-
route as Schmock.RouteKey,
|
|
156
|
-
({ query }) => ({
|
|
157
|
-
results: [],
|
|
158
|
-
query: query.q,
|
|
159
|
-
}),
|
|
160
|
-
{ contentType: "application/json" },
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
When("I request {string}", async (_, request: string) => {
|
|
165
|
-
const [method, fullPath] = request.split(" ");
|
|
166
|
-
const [path, queryString] = fullPath.split("?");
|
|
167
|
-
|
|
168
|
-
const query: Record<string, string> = {};
|
|
169
|
-
if (queryString) {
|
|
170
|
-
queryString.split("&").forEach((param) => {
|
|
171
|
-
const [key, value] = param.split("=");
|
|
172
|
-
query[key] = value;
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
response = await mock.handle(method as any, path, { query });
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
Then("I should receive:", (_, docString: string) => {
|
|
180
|
-
const expected = JSON.parse(docString);
|
|
181
|
-
expect(response.body).toEqual(expected);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
Scenario("Request headers access", ({ Given, When, Then }) => {
|
|
186
|
-
Given("I create a mock that reads headers at {string}", (_, route: string) => {
|
|
187
|
-
mock = schmock({});
|
|
188
|
-
mock(
|
|
189
|
-
route as Schmock.RouteKey,
|
|
190
|
-
({ headers }) => ({
|
|
191
|
-
authenticated: headers.authorization === "Bearer token123",
|
|
192
|
-
}),
|
|
193
|
-
{ contentType: "application/json" },
|
|
194
|
-
);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
When(
|
|
198
|
-
"I request {string} with headers:",
|
|
199
|
-
async (_, request: string, docString: string) => {
|
|
200
|
-
const [method, path] = request.split(" ");
|
|
201
|
-
const headers = JSON.parse(docString);
|
|
202
|
-
response = await mock.handle(method as any, path, { headers });
|
|
203
|
-
},
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
Then("I should receive:", (_, docString: string) => {
|
|
207
|
-
const expected = JSON.parse(docString);
|
|
208
|
-
expect(response.body).toEqual(expected);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
Scenario("Global configuration with namespace", ({ Given, When, Then }) => {
|
|
213
|
-
Given("I create a mock with namespace {string}", (_, namespace: string) => {
|
|
214
|
-
mock = schmock({ namespace });
|
|
215
|
-
mock("GET /users", () => [], { contentType: "application/json" });
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
When("I request {string}", async (_, request: string) => {
|
|
219
|
-
const [method, path] = request.split(" ");
|
|
220
|
-
response = await mock.handle(method as any, path);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
Then("I should receive:", (_, docString: string) => {
|
|
224
|
-
const expected = JSON.parse(docString);
|
|
225
|
-
expect(response.body).toEqual(expected);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
Scenario("Plugin pipeline with pipe chaining", ({ Given, When, Then }) => {
|
|
230
|
-
Given("I create a mock with two passthrough plugins", () => {
|
|
231
|
-
mock = schmock({});
|
|
232
|
-
mock("GET /users", () => [{ id: 1, name: "John" }], {
|
|
233
|
-
contentType: "application/json",
|
|
234
|
-
})
|
|
235
|
-
.pipe({
|
|
236
|
-
name: "logging",
|
|
237
|
-
process: (ctx, response) => ({ context: ctx, response }),
|
|
238
|
-
})
|
|
239
|
-
.pipe({
|
|
240
|
-
name: "cors",
|
|
241
|
-
process: (ctx, response) => ({ context: ctx, response }),
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
When("I request {string}", async (_, request: string) => {
|
|
246
|
-
const [method, path] = request.split(" ");
|
|
247
|
-
response = await mock.handle(method as any, path);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
Then("I should receive:", (_, docString: string) => {
|
|
251
|
-
const expected = JSON.parse(docString);
|
|
252
|
-
expect(response.body).toEqual(expected);
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
});
|