@schmock/core 2.0.0 → 2.0.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/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +3 -0
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +26 -9
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/builder.ts +3 -0
- package/src/helpers.test.ts +41 -0
- package/src/interceptor.test.ts +131 -0
- package/src/interceptor.ts +29 -9
- package/src/parser.property.test.ts +101 -0
- package/src/response-parsing.test.ts +74 -0
- package/src/server.test.ts +49 -0
- package/src/steps/async-support.steps.ts +0 -35
- package/src/steps/basic-usage.steps.ts +0 -84
- package/src/steps/developer-experience.steps.ts +0 -269
- package/src/steps/error-handling.steps.ts +0 -66
- package/src/steps/http-methods.steps.ts +0 -66
- package/src/steps/request-history.steps.ts +0 -75
- package/src/steps/route-key-format.steps.ts +0 -19
- package/src/types.ts +1 -0
|
@@ -64,41 +64,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
Scenario("Multiple async generators in different routes", ({ Given, When, Then, And }) => {
|
|
68
|
-
Given("I create a mock with async routes for posts and comments", () => {
|
|
69
|
-
mock = schmock();
|
|
70
|
-
mock("GET /async-posts", async () => {
|
|
71
|
-
await new Promise(resolve => setTimeout(resolve, 5));
|
|
72
|
-
return [{ id: 1, title: "First Post" }];
|
|
73
|
-
});
|
|
74
|
-
mock("GET /async-comments", async () => {
|
|
75
|
-
await new Promise(resolve => setTimeout(resolve, 8));
|
|
76
|
-
return [{ id: 1, comment: "Great post!" }];
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
When("I make concurrent requests to {string} and {string}", async (_, path1: string, path2: string) => {
|
|
81
|
-
const [posts, comments] = await Promise.all([
|
|
82
|
-
mock.handle("GET", path1),
|
|
83
|
-
mock.handle("GET", path2),
|
|
84
|
-
]);
|
|
85
|
-
responses = [posts, comments];
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
Then("both responses should be returned successfully", () => {
|
|
89
|
-
expect(responses[0].status).toBe(200);
|
|
90
|
-
expect(responses[1].status).toBe(200);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
And("the posts response should contain {string}", (_, text: string) => {
|
|
94
|
-
expect(JSON.stringify(responses[0].body)).toContain(text);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
And("the comments response should contain {string}", (_, text: string) => {
|
|
98
|
-
expect(JSON.stringify(responses[1].body)).toContain(text);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
67
|
Scenario("Async plugin processing", ({ Given, When, Then, And }) => {
|
|
103
68
|
Given("I create a mock with an async processing plugin at {string}", (_, route: string) => {
|
|
104
69
|
const [method, path] = route.split(" ");
|
|
@@ -110,90 +110,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
110
110
|
});
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
Scenario("Undefined response", ({ Given, When, Then, And }) => {
|
|
114
|
-
Given("I create a mock returning undefined at {string}", (_, route: string) => {
|
|
115
|
-
const [method, path] = route.split(" ");
|
|
116
|
-
mock = schmock();
|
|
117
|
-
mock(`${method} ${path}` as Schmock.RouteKey, undefined);
|
|
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 empty response", () => {
|
|
126
|
-
expect(response.body).toBeUndefined();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
And("the status should be {int}", (_, status: number) => {
|
|
130
|
-
expect(response.status).toBe(status);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
Scenario("Empty string response", ({ Given, When, Then, And }) => {
|
|
135
|
-
Given("I create a mock returning empty string at {string}", (_, route: string) => {
|
|
136
|
-
const [method, path] = route.split(" ");
|
|
137
|
-
mock = schmock();
|
|
138
|
-
mock(`${method} ${path}` as Schmock.RouteKey, "");
|
|
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("I should receive text {string}", (_, expectedText: string) => {
|
|
147
|
-
expect(response.body).toBe(expectedText);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
151
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
Scenario("Number response", ({ Given, When, Then, And }) => {
|
|
156
|
-
Given("I create a mock returning number {int} at {string}", (_, num: number, route: string) => {
|
|
157
|
-
const [method, path] = route.split(" ");
|
|
158
|
-
mock = schmock();
|
|
159
|
-
mock(`${method} ${path}` as Schmock.RouteKey, num);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
When("I request {string}", async (_, request: string) => {
|
|
163
|
-
const [method, path] = request.split(" ");
|
|
164
|
-
response = await mock.handle(method as any, path);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
168
|
-
expect(response.body).toBe(expectedText);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
172
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
Scenario("Boolean response", ({ Given, When, Then, And }) => {
|
|
177
|
-
Given("I create a mock returning boolean true at {string}", (_, route: string) => {
|
|
178
|
-
const [method, path] = route.split(" ");
|
|
179
|
-
mock = schmock();
|
|
180
|
-
mock(`${method} ${path}` as Schmock.RouteKey, true);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
When("I request {string}", async (_, request: string) => {
|
|
184
|
-
const [method, path] = request.split(" ");
|
|
185
|
-
response = await mock.handle(method as any, path);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
189
|
-
expect(response.body).toBe(expectedText);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
193
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
113
|
Scenario("Function returning string", ({ Given, When, Then }) => {
|
|
198
114
|
Given("I create a mock with a string generator at {string}", (_, route: string) => {
|
|
199
115
|
const [method, path] = route.split(" ");
|
|
@@ -10,134 +10,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
10
10
|
let response: any;
|
|
11
11
|
let responses: any[] = [];
|
|
12
12
|
|
|
13
|
-
Scenario("Forgetting to provide response data", ({ Given, When, Then, And }) => {
|
|
14
|
-
Given("I create a mock with no response data on {string}", (_, route: string) => {
|
|
15
|
-
mock = schmock();
|
|
16
|
-
mock(route as Schmock.RouteKey, undefined);
|
|
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 status {int}", (_, status: number) => {
|
|
25
|
-
expect(response.status).toBe(status);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
And("the response body should be empty", () => {
|
|
29
|
-
expect(response.body).toBeUndefined();
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
Scenario("Using wrong parameter name in route", ({ Given, When, Then }) => {
|
|
34
|
-
Given("I create a mock with a mismatched parameter name on {string}", (_, route: string) => {
|
|
35
|
-
mock = schmock();
|
|
36
|
-
mock(route as Schmock.RouteKey, ({ params }) => ({ id: params.id }));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
When("I request {string}", async (_, request: string) => {
|
|
40
|
-
const [method, path] = request.split(" ");
|
|
41
|
-
response = await mock.handle(method as any, path);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
Then("the wrong parameter should be undefined", () => {
|
|
45
|
-
expect(response.body).toEqual({ id: undefined });
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
Scenario("Correct parameter usage", ({ Given, When, Then }) => {
|
|
50
|
-
Given("I create a mock with a matching parameter name on {string}", (_, route: string) => {
|
|
51
|
-
mock = schmock();
|
|
52
|
-
mock(route as Schmock.RouteKey, ({ params }) => ({ id: params.userId }));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
When("I request {string}", async (_, request: string) => {
|
|
56
|
-
const [method, path] = request.split(" ");
|
|
57
|
-
response = await mock.handle(method as any, path);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
Then("I should receive:", (_, docString: string) => {
|
|
61
|
-
const expected = JSON.parse(docString);
|
|
62
|
-
expect(response.body).toEqual(expected);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
Scenario("Mixing content types without explicit configuration", ({ Given, When, Then, And }) => {
|
|
67
|
-
Given("I create a mock with JSON, text, number, and boolean routes", () => {
|
|
68
|
-
mock = schmock();
|
|
69
|
-
mock("GET /json", { data: "json" });
|
|
70
|
-
mock("GET /text", "plain text");
|
|
71
|
-
mock("GET /number", 42);
|
|
72
|
-
mock("GET /boolean", true);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
When("I test all mixed content type routes", async () => {
|
|
76
|
-
responses = [];
|
|
77
|
-
responses.push(await mock.handle("GET", "/json"));
|
|
78
|
-
responses.push(await mock.handle("GET", "/text"));
|
|
79
|
-
responses.push(await mock.handle("GET", "/number"));
|
|
80
|
-
responses.push(await mock.handle("GET", "/boolean"));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
Then("JSON route should have content-type {string}", (_, contentType: string) => {
|
|
84
|
-
expect(responses[0].headers?.["content-type"]).toBe(contentType);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
And("text route should have content-type {string}", (_, contentType: string) => {
|
|
88
|
-
expect(responses[1].headers?.["content-type"]).toBe(contentType);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
And("number route should have content-type {string}", (_, contentType: string) => {
|
|
92
|
-
expect(responses[2].headers?.["content-type"]).toBe(contentType);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
And("boolean route should have content-type {string}", (_, contentType: string) => {
|
|
96
|
-
expect(responses[3].headers?.["content-type"]).toBe(contentType);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
Scenario("Expecting JSON but getting string conversion", ({ Given, When, Then, And }) => {
|
|
101
|
-
Given("I create a mock returning a decimal number on {string}", (_, route: string) => {
|
|
102
|
-
mock = schmock();
|
|
103
|
-
mock(route as Schmock.RouteKey, 19.99);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
When("I request {string}", async (_, request: string) => {
|
|
107
|
-
const [method, path] = request.split(" ");
|
|
108
|
-
response = await mock.handle(method as any, path);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
Then("I should receive text {string}", (_, expectedText: string) => {
|
|
112
|
-
expect(response.body).toBe(expectedText);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
116
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
Scenario("Forgetting await with async generators", ({ Given, When, Then, And }) => {
|
|
121
|
-
Given("I create a mock with an async handler on {string}", (_, route: string) => {
|
|
122
|
-
mock = schmock();
|
|
123
|
-
mock(route as Schmock.RouteKey, async () => ({ async: true }));
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
When("I request {string}", async (_, request: string) => {
|
|
127
|
-
const [method, path] = request.split(" ");
|
|
128
|
-
response = await mock.handle(method as any, path);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
Then("I should receive:", (_, docString: string) => {
|
|
132
|
-
const expected = JSON.parse(docString);
|
|
133
|
-
expect(response.body).toEqual(expected);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
And("the content-type should be {string}", (_, contentType: string) => {
|
|
137
|
-
expect(response.headers?.["content-type"]).toBe(contentType);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
13
|
Scenario("State confusion between global and local state", ({ Given, When, Then, And }) => {
|
|
142
14
|
Given("I create a mock with global state and a local state counter", () => {
|
|
143
15
|
mock = schmock({ state: { global: 1 } });
|
|
@@ -166,62 +38,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
166
38
|
});
|
|
167
39
|
});
|
|
168
40
|
|
|
169
|
-
Scenario("Query parameter edge cases", ({ Given, When, Then }) => {
|
|
170
|
-
Given("I create a mock that echoes query parameters on {string}", (_, route: string) => {
|
|
171
|
-
mock = schmock();
|
|
172
|
-
mock(route as Schmock.RouteKey, ({ query }) => ({
|
|
173
|
-
term: query.q,
|
|
174
|
-
page: query.page,
|
|
175
|
-
empty: query.empty,
|
|
176
|
-
}));
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
When("I request {string}", async (_, request: string) => {
|
|
180
|
-
const [method, fullPath] = request.split(" ");
|
|
181
|
-
const [path, queryString] = fullPath.split("?");
|
|
182
|
-
|
|
183
|
-
const query: Record<string, string> = {};
|
|
184
|
-
if (queryString) {
|
|
185
|
-
queryString.split("&").forEach((param) => {
|
|
186
|
-
const [key, value] = param.split("=");
|
|
187
|
-
query[key] = value || "";
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
response = await mock.handle(method as any, path, { query });
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
Then("I should receive:", (_, docString: string) => {
|
|
195
|
-
const expected = JSON.parse(docString);
|
|
196
|
-
expect(response.body).toEqual(expected);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
Scenario("Headers case sensitivity", ({ Given, When, Then }) => {
|
|
201
|
-
Given("I create a mock that echoes headers on {string}", (_, route: string) => {
|
|
202
|
-
mock = schmock();
|
|
203
|
-
mock(route as Schmock.RouteKey, ({ headers }) => ({
|
|
204
|
-
auth: headers.authorization,
|
|
205
|
-
authUpper: headers.Authorization,
|
|
206
|
-
contentType: headers["content-type"],
|
|
207
|
-
}));
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
When("I request {string} with headers:", async (_, request: string, docString: string) => {
|
|
211
|
-
const [method, path] = request.split(" ");
|
|
212
|
-
const headers = JSON.parse(docString);
|
|
213
|
-
response = await mock.handle(method as any, path, { headers });
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
Then("the header case sensitivity should show expected values", () => {
|
|
217
|
-
expect(response.body).toEqual({
|
|
218
|
-
auth: undefined,
|
|
219
|
-
authUpper: "Bearer token",
|
|
220
|
-
contentType: undefined,
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
41
|
Scenario("Route precedence with similar paths", ({ Given, When, Then, And }) => {
|
|
226
42
|
Given("I create a mock with an exact route and a parameterized route on {string}", (_, basePath: string) => {
|
|
227
43
|
mock = schmock();
|
|
@@ -277,28 +93,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
277
93
|
});
|
|
278
94
|
});
|
|
279
95
|
|
|
280
|
-
Scenario("Namespace confusion with absolute paths", ({ Given, When, Then, And }) => {
|
|
281
|
-
Given("I create a mock with namespace {string} and a users route", (_, namespace: string) => {
|
|
282
|
-
mock = schmock({ namespace });
|
|
283
|
-
mock("GET /users", []);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
When("I test both namespace scenarios", async () => {
|
|
287
|
-
responses = [];
|
|
288
|
-
responses.push(await mock.handle("GET", "/users"));
|
|
289
|
-
responses.push(await mock.handle("GET", "/api/v1/users"));
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
Then("the wrong namespace should receive status {int}", (_, status: number) => {
|
|
293
|
-
expect(responses[0].status).toBe(status);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
And("the correct namespace should receive:", (_, docString: string) => {
|
|
297
|
-
const expected = JSON.parse(docString);
|
|
298
|
-
expect(responses[1].body).toEqual(expected);
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
96
|
Scenario("Plugin expecting different context structure", ({ Given, When, Then }) => {
|
|
303
97
|
Given("I create a mock with a plugin that reads context properties", () => {
|
|
304
98
|
mock = schmock();
|
|
@@ -371,46 +165,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
371
165
|
});
|
|
372
166
|
});
|
|
373
167
|
|
|
374
|
-
Scenario("Common typos in method names", ({ Given, When, Then, And }) => {
|
|
375
|
-
let errors: Error[] = [];
|
|
376
|
-
|
|
377
|
-
Given("I create an empty mock for testing method typos", () => {
|
|
378
|
-
mock = schmock();
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
When("I test all common method typos", () => {
|
|
382
|
-
errors = [];
|
|
383
|
-
const typos = ["GETS /users", "post /users", "GET/users"];
|
|
384
|
-
|
|
385
|
-
for (const typo of typos) {
|
|
386
|
-
try {
|
|
387
|
-
mock(typo as Schmock.RouteKey, "test");
|
|
388
|
-
errors.push(new Error("No error thrown"));
|
|
389
|
-
} catch (e) {
|
|
390
|
-
errors.push(e as Error);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
Then("the wrong method typo should throw RouteParseError", () => {
|
|
396
|
-
expect(errors[0]).not.toBeNull();
|
|
397
|
-
expect(errors[0].constructor.name).toBe("RouteParseError");
|
|
398
|
-
expect(errors[0].message).toContain("Invalid route key format");
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
And("the lowercase method typo should throw RouteParseError", () => {
|
|
402
|
-
expect(errors[1]).not.toBeNull();
|
|
403
|
-
expect(errors[1].constructor.name).toBe("RouteParseError");
|
|
404
|
-
expect(errors[1].message).toContain("Invalid route key format");
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
And("the missing space typo should throw RouteParseError", () => {
|
|
408
|
-
expect(errors[2]).not.toBeNull();
|
|
409
|
-
expect(errors[2].constructor.name).toBe("RouteParseError");
|
|
410
|
-
expect(errors[2].message).toContain("Invalid route key format");
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
|
|
414
168
|
Scenario("Registering duplicate routes first route wins", ({ Given, When, Then }) => {
|
|
415
169
|
Given("I create a mock with two routes on {string} with different data", (_, route: string) => {
|
|
416
170
|
mock = schmock();
|
|
@@ -429,27 +183,4 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
429
183
|
});
|
|
430
184
|
});
|
|
431
185
|
|
|
432
|
-
Scenario("Plugin returning unexpected structure", ({ Given, When, Then, And }) => {
|
|
433
|
-
Given("I create a mock with a plugin that returns an invalid structure", () => {
|
|
434
|
-
mock = schmock();
|
|
435
|
-
const badPlugin = {
|
|
436
|
-
name: "bad-structure",
|
|
437
|
-
process: () => ({ wrong: "structure" }),
|
|
438
|
-
};
|
|
439
|
-
mock("GET /bad", "original").pipe(badPlugin as any);
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
When("I request {string}", async (_, request: string) => {
|
|
443
|
-
const [method, path] = request.split(" ");
|
|
444
|
-
response = await mock.handle(method as any, path);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
Then("I should receive status {int}", (_, status: number) => {
|
|
448
|
-
expect(response.status).toBe(status);
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
And("the response should contain error {string}", (_, errorMessage: string) => {
|
|
452
|
-
expect(response.body.error).toContain(errorMessage);
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
186
|
});
|
|
@@ -8,7 +8,6 @@ const feature = await loadFeature("../../features/error-handling.feature");
|
|
|
8
8
|
describeFeature(feature, ({ Scenario }) => {
|
|
9
9
|
let mock: CallableMockInstance;
|
|
10
10
|
let response: any;
|
|
11
|
-
let error: Error | null = null;
|
|
12
11
|
|
|
13
12
|
Scenario("Route not found returns 404", ({ Given, When, Then, And }) => {
|
|
14
13
|
Given("I create a mock with a GET /users route returning a user list", () => {
|
|
@@ -54,48 +53,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
54
53
|
});
|
|
55
54
|
});
|
|
56
55
|
|
|
57
|
-
Scenario("Invalid route key throws RouteDefinitionError", ({ Given, Then, And }) => {
|
|
58
|
-
Given("I attempt to register a route with an invalid HTTP method", () => {
|
|
59
|
-
error = null;
|
|
60
|
-
try {
|
|
61
|
-
mock = schmock();
|
|
62
|
-
mock("INVALID_METHOD /path" as any, "response");
|
|
63
|
-
} catch (e) {
|
|
64
|
-
error = e as Error;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
Then("it should throw a RouteDefinitionError", () => {
|
|
69
|
-
expect(error).not.toBeNull();
|
|
70
|
-
expect(error!.constructor.name).toBe("RouteParseError");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
And("the error message should contain {string}", (_, message: string) => {
|
|
74
|
-
expect(error!.message).toContain("Invalid route key format");
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
Scenario("Empty route path throws RouteDefinitionError", ({ Given, Then, And }) => {
|
|
79
|
-
Given("I attempt to register a route with an empty path", () => {
|
|
80
|
-
error = null;
|
|
81
|
-
try {
|
|
82
|
-
mock = schmock();
|
|
83
|
-
mock("GET " as any, "response");
|
|
84
|
-
} catch (e) {
|
|
85
|
-
error = e as Error;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
Then("it should throw a RouteDefinitionError", () => {
|
|
90
|
-
expect(error).not.toBeNull();
|
|
91
|
-
expect(error!.constructor.name).toBe("RouteParseError");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
And("the error message should contain {string}", (_, message: string) => {
|
|
95
|
-
expect(error!.message).toContain("Invalid route key format");
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
56
|
Scenario("Plugin throws error returns 500 with PluginError", ({ Given, When, Then, And }) => {
|
|
100
57
|
Given("I create a mock with a plugin that throws {string}", (_, errorMsg: string) => {
|
|
101
58
|
mock = schmock();
|
|
@@ -197,29 +154,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
197
154
|
});
|
|
198
155
|
});
|
|
199
156
|
|
|
200
|
-
Scenario("Invalid JSON generator with JSON content-type throws RouteDefinitionError", ({ Given, Then, And }) => {
|
|
201
|
-
Given("I attempt to register a route with a circular reference as JSON", () => {
|
|
202
|
-
error = null;
|
|
203
|
-
try {
|
|
204
|
-
mock = schmock();
|
|
205
|
-
const circularRef: Record<string, unknown> = {};
|
|
206
|
-
circularRef.self = circularRef;
|
|
207
|
-
mock("GET /invalid", circularRef, { contentType: "application/json" });
|
|
208
|
-
} catch (e) {
|
|
209
|
-
error = e as Error;
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
Then("it should throw a RouteDefinitionError", () => {
|
|
214
|
-
expect(error).not.toBeNull();
|
|
215
|
-
expect(error!.constructor.name).toBe("RouteDefinitionError");
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
And("the error message should contain {string}", (_, message: string) => {
|
|
219
|
-
expect(error!.message).toContain(message);
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
157
|
Scenario("Namespace mismatch returns 404", ({ Given, When, Then, And }) => {
|
|
224
158
|
Given("I create a mock with namespace {string} and a GET /users route", (_, namespace: string) => {
|
|
225
159
|
mock = schmock({ namespace });
|
|
@@ -9,7 +9,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
9
9
|
let mock: CallableMockInstance;
|
|
10
10
|
let response: any;
|
|
11
11
|
let responses: any[] = [];
|
|
12
|
-
let error: Error | null = null;
|
|
13
12
|
|
|
14
13
|
Scenario("GET method with query parameters", ({ Given, When, Then }) => {
|
|
15
14
|
Given("I create a mock with a GET search endpoint", () => {
|
|
@@ -255,71 +254,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
255
254
|
});
|
|
256
255
|
});
|
|
257
256
|
|
|
258
|
-
Scenario("Method case sensitivity", ({ Given, When, Then }) => {
|
|
259
|
-
error = null;
|
|
260
|
-
|
|
261
|
-
Given("I create an empty mock for case sensitivity testing", () => {
|
|
262
|
-
mock = schmock();
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
When("I attempt to create a mock with lowercase method", () => {
|
|
266
|
-
error = null;
|
|
267
|
-
try {
|
|
268
|
-
mock('get /test' as Schmock.RouteKey, { method: 'get' });
|
|
269
|
-
} catch (e) {
|
|
270
|
-
error = e as Error;
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
Then("it should throw RouteParseError for invalid method case", () => {
|
|
275
|
-
expect(error).not.toBeNull();
|
|
276
|
-
expect(error!.constructor.name).toBe('RouteParseError');
|
|
277
|
-
expect(error!.message).toContain('Invalid route key format');
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
Scenario("Unsupported HTTP methods", ({ Given, When, Then }) => {
|
|
282
|
-
error = null;
|
|
283
|
-
|
|
284
|
-
Given("I create an empty mock for unsupported method testing", () => {
|
|
285
|
-
mock = schmock();
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
When("I attempt to create a mock with unsupported method", () => {
|
|
289
|
-
error = null;
|
|
290
|
-
try {
|
|
291
|
-
mock('CUSTOM /endpoint' as Schmock.RouteKey, { custom: true });
|
|
292
|
-
} catch (e) {
|
|
293
|
-
error = e as Error;
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
Then("it should throw RouteParseError for unsupported method", () => {
|
|
298
|
-
expect(error).not.toBeNull();
|
|
299
|
-
expect(error!.constructor.name).toBe('RouteParseError');
|
|
300
|
-
expect(error!.message).toContain('Invalid route key format');
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
Scenario("Method with special characters in path", ({ Given, When, Then }) => {
|
|
305
|
-
Given("I create a mock with nested parameterized path segments", () => {
|
|
306
|
-
mock = schmock();
|
|
307
|
-
mock('GET /api/v1/users/:id/posts/:post-id', ({ params }) => ({
|
|
308
|
-
userId: params.id,
|
|
309
|
-
postId: params['post-id'],
|
|
310
|
-
}));
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
When("I make a GET request to {string}", async (_, path: string) => {
|
|
314
|
-
response = await mock.handle('GET', path);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
Then("I should receive special characters response:", (_, docString: string) => {
|
|
318
|
-
const expected = JSON.parse(docString);
|
|
319
|
-
expect(response.body).toEqual(expected);
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
257
|
Scenario("Method with request headers validation", ({ Given, When, Then, And }) => {
|
|
324
258
|
Given("I create a mock with authorization header checking", () => {
|
|
325
259
|
mock = schmock();
|
|
@@ -9,57 +9,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
9
9
|
let mock: CallableMockInstance;
|
|
10
10
|
let response: any;
|
|
11
11
|
|
|
12
|
-
Scenario("No requests recorded initially", ({ Given, Then, And }) => {
|
|
13
|
-
Given("I create a mock with a single GET route for history", () => {
|
|
14
|
-
mock = schmock();
|
|
15
|
-
mock("GET /users", [{ id: 1 }]);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
Then("the mock should not have been called", () => {
|
|
19
|
-
expect(mock.called()).toBe(false);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
And("the call count should be 0", () => {
|
|
23
|
-
expect(mock.callCount()).toBe(0);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
And("the history should be empty", () => {
|
|
27
|
-
expect(mock.history()).toEqual([]);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
Scenario("Record a single GET request", ({ Given, When, Then, And }) => {
|
|
32
|
-
Given("I create a mock returning users at {string}", (_, route: string) => {
|
|
33
|
-
mock = schmock();
|
|
34
|
-
mock(route as Schmock.RouteKey, [{ id: 1, name: "John" }]);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
When("I request {string}", async (_, request: string) => {
|
|
38
|
-
const [method, path] = request.split(" ");
|
|
39
|
-
response = await mock.handle(method as any, path);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
Then("the mock should have been called", () => {
|
|
43
|
-
expect(mock.called()).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
And("the call count should be 1", () => {
|
|
47
|
-
expect(mock.callCount()).toBe(1);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
And("the history should have 1 entry", () => {
|
|
51
|
-
expect(mock.history()).toHaveLength(1);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
And("the last request method should be {string}", (_, method: string) => {
|
|
55
|
-
expect(mock.lastRequest()?.method).toBe(method);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
And("the last request path should be {string}", (_, path: string) => {
|
|
59
|
-
expect(mock.lastRequest()?.path).toBe(path);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
12
|
Scenario("Record multiple requests", ({ Given, When, And, Then }) => {
|
|
64
13
|
Given("I create a mock with GET and POST user routes", () => {
|
|
65
14
|
mock = schmock();
|
|
@@ -287,30 +236,6 @@ describeFeature(feature, ({ Scenario }) => {
|
|
|
287
236
|
);
|
|
288
237
|
});
|
|
289
238
|
|
|
290
|
-
Scenario("History works with namespaced mocks", ({ Given, When, Then, And }) => {
|
|
291
|
-
Given("I create a namespaced mock under {string}", (_, namespace: string) => {
|
|
292
|
-
mock = schmock({ namespace });
|
|
293
|
-
mock("GET /users", [{ id: 1 }]);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
When("I request {string}", async (_, request: string) => {
|
|
297
|
-
const [method, path] = request.split(" ");
|
|
298
|
-
response = await mock.handle(method as any, path);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
Then("the mock should have been called", () => {
|
|
302
|
-
expect(mock.called()).toBe(true);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
And("the call count should be 1", () => {
|
|
306
|
-
expect(mock.callCount()).toBe(1);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
And("the last request path should be {string}", (_, path: string) => {
|
|
310
|
-
expect(mock.lastRequest()?.path).toBe(path);
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
239
|
Scenario("404 requests are not recorded in history", ({ Given, When, Then, And }) => {
|
|
315
240
|
Given("I create a mock with only a users route", () => {
|
|
316
241
|
mock = schmock();
|