@schmock/core 1.0.3 → 1.1.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.
Files changed (39) hide show
  1. package/dist/builder.d.ts +13 -5
  2. package/dist/builder.d.ts.map +1 -1
  3. package/dist/builder.js +147 -60
  4. package/dist/constants.d.ts +6 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/constants.js +20 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +3 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +20 -11
  12. package/dist/parser.d.ts.map +1 -1
  13. package/dist/parser.js +2 -17
  14. package/dist/types.d.ts +17 -210
  15. package/dist/types.d.ts.map +1 -1
  16. package/dist/types.js +1 -0
  17. package/package.json +4 -4
  18. package/src/builder.test.ts +2 -2
  19. package/src/builder.ts +232 -108
  20. package/src/constants.test.ts +59 -0
  21. package/src/constants.ts +25 -0
  22. package/src/errors.ts +3 -1
  23. package/src/index.ts +41 -29
  24. package/src/namespace.test.ts +3 -2
  25. package/src/parser.property.test.ts +495 -0
  26. package/src/parser.ts +2 -20
  27. package/src/route-matching.test.ts +1 -1
  28. package/src/steps/async-support.steps.ts +101 -91
  29. package/src/steps/basic-usage.steps.ts +49 -36
  30. package/src/steps/developer-experience.steps.ts +110 -94
  31. package/src/steps/error-handling.steps.ts +90 -66
  32. package/src/steps/fluent-api.steps.ts +75 -72
  33. package/src/steps/http-methods.steps.ts +33 -33
  34. package/src/steps/performance-reliability.steps.ts +52 -88
  35. package/src/steps/plugin-integration.steps.ts +176 -176
  36. package/src/steps/request-history.steps.ts +333 -0
  37. package/src/steps/state-concurrency.steps.ts +418 -316
  38. package/src/steps/stateful-workflows.steps.ts +138 -136
  39. package/src/types.ts +20 -259
@@ -1,7 +1,7 @@
1
1
  import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
2
  import { expect } from "vitest";
3
3
  import { schmock } from "../index";
4
- import type { CallableMockInstance } from "../types";
4
+ import type { CallableMockInstance, Plugin } from "../types";
5
5
 
6
6
  const feature = await loadFeature("../../features/async-support.feature");
7
7
 
@@ -13,11 +13,12 @@ describeFeature(feature, ({ Scenario }) => {
13
13
  let endTime: number;
14
14
 
15
15
  Scenario("Async generator function returns Promise", ({ Given, When, Then, And }) => {
16
- Given("I create a mock with async generator:", (_, docString: string) => {
16
+ Given("I create a mock with an async generator at {string}", (_, route: string) => {
17
+ const [method, path] = route.split(" ");
17
18
  mock = schmock();
18
- mock('GET /async-data', async () => {
19
+ mock(`${method} ${path}` as any, async () => {
19
20
  await new Promise(resolve => setTimeout(resolve, 10));
20
- return { message: 'async response' };
21
+ return { message: "async response" };
21
22
  });
22
23
  });
23
24
 
@@ -37,13 +38,14 @@ describeFeature(feature, ({ Scenario }) => {
37
38
  });
38
39
 
39
40
  Scenario("Async generator with context access", ({ Given, When, Then, And }) => {
40
- Given("I create a mock with async context generator:", (_, docString: string) => {
41
+ Given("I create a mock with an async param-based generator at {string}", (_, route: string) => {
42
+ const [method, path] = route.split(" ");
41
43
  mock = schmock();
42
- mock('GET /async-user/:id', async ({ params }) => {
44
+ mock(`${method} ${path}` as any, async ({ params }: any) => {
43
45
  await new Promise(resolve => setTimeout(resolve, 5));
44
- return {
45
- userId: params.id,
46
- fetchedAt: new Date().toISOString()
46
+ return {
47
+ userId: params.id,
48
+ fetchedAt: new Date().toISOString(),
47
49
  };
48
50
  });
49
51
  });
@@ -63,22 +65,22 @@ describeFeature(feature, ({ Scenario }) => {
63
65
  });
64
66
 
65
67
  Scenario("Multiple async generators in different routes", ({ Given, When, Then, And }) => {
66
- Given("I create a mock with multiple async routes:", (_, docString: string) => {
68
+ Given("I create a mock with async routes for posts and comments", () => {
67
69
  mock = schmock();
68
- mock('GET /async-posts', async () => {
70
+ mock("GET /async-posts", async () => {
69
71
  await new Promise(resolve => setTimeout(resolve, 5));
70
- return [{ id: 1, title: 'First Post' }];
72
+ return [{ id: 1, title: "First Post" }];
71
73
  });
72
- mock('GET /async-comments', async () => {
74
+ mock("GET /async-comments", async () => {
73
75
  await new Promise(resolve => setTimeout(resolve, 8));
74
- return [{ id: 1, comment: 'Great post!' }];
76
+ return [{ id: 1, comment: "Great post!" }];
75
77
  });
76
78
  });
77
79
 
78
80
  When("I make concurrent requests to {string} and {string}", async (_, path1: string, path2: string) => {
79
81
  const [posts, comments] = await Promise.all([
80
- mock.handle('GET', path1),
81
- mock.handle('GET', path2)
82
+ mock.handle("GET", path1),
83
+ mock.handle("GET", path2),
82
84
  ]);
83
85
  responses = [posts, comments];
84
86
  });
@@ -98,23 +100,24 @@ describeFeature(feature, ({ Scenario }) => {
98
100
  });
99
101
 
100
102
  Scenario("Async plugin processing", ({ Given, When, Then, And }) => {
101
- Given("I create a mock with async plugin:", (_, docString: string) => {
103
+ Given("I create a mock with an async processing plugin at {string}", (_, route: string) => {
104
+ const [method, path] = route.split(" ");
102
105
  mock = schmock();
103
- const asyncPlugin = {
104
- name: 'async-processor',
105
- process: async (ctx: any, response: any) => {
106
+ const asyncPlugin: Plugin = {
107
+ name: "async-processor",
108
+ process: async (ctx, response) => {
106
109
  await new Promise(resolve => setTimeout(resolve, 5));
107
110
  return {
108
111
  context: ctx,
109
112
  response: {
110
113
  data: response,
111
114
  processedAsync: true,
112
- timestamp: new Date().toISOString()
113
- }
115
+ timestamp: new Date().toISOString(),
116
+ },
114
117
  };
115
- }
118
+ },
116
119
  };
117
- mock('GET /processed', { original: 'data' }).pipe(asyncPlugin);
120
+ mock(`${method} ${path}` as any, { original: "data" }).pipe(asyncPlugin);
118
121
  });
119
122
 
120
123
  When("I request {string}", async (_, request: string) => {
@@ -127,7 +130,7 @@ describeFeature(feature, ({ Scenario }) => {
127
130
  });
128
131
 
129
132
  And("the async response should have property {string} with value {word}", (_, property: string, value: string) => {
130
- const expectedValue = value === 'true' ? true : value === 'false' ? false : value;
133
+ const expectedValue = value === "true" ? true : value === "false" ? false : value;
131
134
  expect(response.body).toHaveProperty(property, expectedValue);
132
135
  });
133
136
 
@@ -137,26 +140,27 @@ describeFeature(feature, ({ Scenario }) => {
137
140
  });
138
141
 
139
142
  Scenario("Mixed sync and async plugin pipeline", ({ Given, When, Then, And }) => {
140
- Given("I create a mock with mixed plugin pipeline:", (_, docString: string) => {
143
+ Given("I create a mock with sync and async plugins at {string}", (_, route: string) => {
144
+ const [method, path] = route.split(" ");
141
145
  mock = schmock();
142
- const syncPlugin = {
143
- name: 'sync-step',
144
- process: (ctx: any, response: any) => ({
146
+ const syncPlugin: Plugin = {
147
+ name: "sync-step",
148
+ process: (ctx, response) => ({
145
149
  context: ctx,
146
- response: { ...response, syncStep: true }
147
- })
150
+ response: { ...response, syncStep: true },
151
+ }),
148
152
  };
149
- const asyncPlugin = {
150
- name: 'async-step',
151
- process: async (ctx: any, response: any) => {
153
+ const asyncPlugin: Plugin = {
154
+ name: "async-step",
155
+ process: async (ctx, response) => {
152
156
  await new Promise(resolve => setTimeout(resolve, 5));
153
157
  return {
154
158
  context: ctx,
155
- response: { ...response, asyncStep: true }
159
+ response: { ...response, asyncStep: true },
156
160
  };
157
- }
161
+ },
158
162
  };
159
- mock('GET /mixed', { base: 'data' })
163
+ mock(`${method} ${path}` as any, { base: "data" })
160
164
  .pipe(syncPlugin)
161
165
  .pipe(asyncPlugin);
162
166
  });
@@ -171,22 +175,23 @@ describeFeature(feature, ({ Scenario }) => {
171
175
  });
172
176
 
173
177
  And("the response should have property {string} with value {word}", (_, property: string, value: string) => {
174
- const expectedValue = value === 'true' ? true : value === 'false' ? false : value;
178
+ const expectedValue = value === "true" ? true : value === "false" ? false : value;
175
179
  expect(response.body).toHaveProperty(property, expectedValue);
176
180
  });
177
181
 
178
182
  And("the response should have property {string} with boolean value {word}", (_, property: string, value: string) => {
179
- const expectedValue = value === 'true' ? true : value === 'false' ? false : value;
183
+ const expectedValue = value === "true" ? true : value === "false" ? false : value;
180
184
  expect(response.body).toHaveProperty(property, expectedValue);
181
185
  });
182
186
  });
183
187
 
184
188
  Scenario("Async generator with Promise rejection", ({ Given, When, Then, And }) => {
185
- Given("I create a mock with failing async generator:", (_, docString: string) => {
189
+ Given("I create a mock with an async generator that throws at {string}", (_, route: string) => {
190
+ const [method, path] = route.split(" ");
186
191
  mock = schmock();
187
- mock('GET /async-fail', async () => {
192
+ mock(`${method} ${path}` as any, async () => {
188
193
  await new Promise(resolve => setTimeout(resolve, 5));
189
- throw new Error('Async operation failed');
194
+ throw new Error("Async operation failed");
190
195
  });
191
196
  });
192
197
 
@@ -205,24 +210,25 @@ describeFeature(feature, ({ Scenario }) => {
205
210
  });
206
211
 
207
212
  Scenario("Async plugin error recovery", ({ Given, When, Then, And }) => {
208
- Given("I create a mock with async error recovery:", (_, docString: string) => {
213
+ Given("I create a mock with an async error-recovery plugin at {string}", (_, route: string) => {
214
+ const [method, path] = route.split(" ");
209
215
  mock = schmock();
210
- const asyncErrorPlugin = {
211
- name: 'async-error-handler',
216
+ const asyncErrorPlugin: Plugin = {
217
+ name: "async-error-handler",
212
218
  process: async () => {
213
219
  await new Promise(resolve => setTimeout(resolve, 5));
214
- throw new Error('Async plugin failed');
220
+ throw new Error("Async plugin failed");
215
221
  },
216
- onError: async (error: Error, ctx: any) => {
222
+ onError: async (error) => {
217
223
  await new Promise(resolve => setTimeout(resolve, 3));
218
224
  return {
219
225
  status: 200,
220
226
  body: { recovered: true, originalError: error.message },
221
- headers: {}
227
+ headers: {},
222
228
  };
223
- }
229
+ },
224
230
  };
225
- mock('GET /async-recovery', 'original').pipe(asyncErrorPlugin);
231
+ mock(`${method} ${path}` as any, "original").pipe(asyncErrorPlugin);
226
232
  });
227
233
 
228
234
  When("I request {string}", async (_, request: string) => {
@@ -235,7 +241,7 @@ describeFeature(feature, ({ Scenario }) => {
235
241
  });
236
242
 
237
243
  And("the response should have property {string} with value {word}", (_, property: string, value: string) => {
238
- const expectedValue = value === 'true' ? true : value === 'false' ? false : value;
244
+ const expectedValue = value === "true" ? true : value === "false" ? false : value;
239
245
  expect(response.body).toHaveProperty(property, expectedValue);
240
246
  });
241
247
 
@@ -245,9 +251,10 @@ describeFeature(feature, ({ Scenario }) => {
245
251
  });
246
252
 
247
253
  Scenario("Async generator with delay configuration", ({ Given, When, Then, And }) => {
248
- Given("I create a mock with async generator and delay:", (_, docString: string) => {
254
+ Given("I create a mock with delay 20ms and async generator at {string}", (_, route: string) => {
255
+ const [method, path] = route.split(" ");
249
256
  mock = schmock({ delay: 20 });
250
- mock('GET /delayed-async', async () => {
257
+ mock(`${method} ${path}` as any, async () => {
251
258
  await new Promise(resolve => setTimeout(resolve, 10));
252
259
  return { delayed: true, async: true };
253
260
  });
@@ -272,14 +279,15 @@ describeFeature(feature, ({ Scenario }) => {
272
279
  });
273
280
 
274
281
  Scenario("Async generator with state management", ({ Given, When, Then, And }) => {
275
- Given("I create a mock with async stateful generator:", (_, docString: string) => {
282
+ Given("I create a mock with async stateful counter at {string}", (_, route: string) => {
283
+ const [method, path] = route.split(" ");
276
284
  mock = schmock({ state: { asyncCounter: 0 } });
277
- mock('GET /async-counter', async ({ state }) => {
285
+ mock(`${method} ${path}` as any, async ({ state }: any) => {
278
286
  await new Promise(resolve => setTimeout(resolve, 5));
279
287
  state.asyncCounter = (state.asyncCounter || 0) + 1;
280
- return {
288
+ return {
281
289
  count: state.asyncCounter,
282
- processedAsync: true
290
+ processedAsync: true,
283
291
  };
284
292
  });
285
293
  });
@@ -300,26 +308,27 @@ describeFeature(feature, ({ Scenario }) => {
300
308
  });
301
309
 
302
310
  And("both responses should have processedAsync {word}", (_, value: string) => {
303
- const expectedValue = value === 'true' ? true : value === 'false' ? false : value;
311
+ const expectedValue = value === "true" ? true : value === "false" ? false : value;
304
312
  expect(responses[0].body.processedAsync).toBe(expectedValue);
305
313
  expect(responses[1].body.processedAsync).toBe(expectedValue);
306
314
  });
307
315
  });
308
316
 
309
317
  Scenario("Promise-based plugin response generation", ({ Given, When, Then }) => {
310
- Given("I create a mock with Promise-generating plugin:", (_, docString: string) => {
318
+ Given("I create a mock with a Promise-generating plugin at {string}", (_, route: string) => {
319
+ const [method, path] = route.split(" ");
311
320
  mock = schmock();
312
- const promisePlugin = {
313
- name: 'promise-generator',
314
- process: async (ctx: any, response: any) => {
321
+ const promisePlugin: Plugin = {
322
+ name: "promise-generator",
323
+ process: async (ctx, response) => {
315
324
  if (!response) {
316
- const data = await Promise.resolve({ generated: 'by promise' });
325
+ const data = await Promise.resolve({ generated: "by promise" });
317
326
  return { context: ctx, response: data };
318
327
  }
319
328
  return { context: ctx, response };
320
- }
329
+ },
321
330
  };
322
- mock('GET /promise-gen', null).pipe(promisePlugin);
331
+ mock(`${method} ${path}` as any, null).pipe(promisePlugin);
323
332
  });
324
333
 
325
334
  When("I request {string}", async (_, request: string) => {
@@ -334,33 +343,33 @@ describeFeature(feature, ({ Scenario }) => {
334
343
  });
335
344
 
336
345
  Scenario("Concurrent async requests isolation", ({ Given, When, Then, And }) => {
337
- Given("I create a mock with async state isolation:", (_, docString: string) => {
346
+ Given("I create a mock with async delay per id at {string}", (_, route: string) => {
347
+ const [method, path] = route.split(" ");
338
348
  mock = schmock();
339
- mock('GET /isolated/:id', async ({ params }) => {
349
+ mock(`${method} ${path}` as any, async ({ params }: any) => {
340
350
  const delay = parseInt(params.id) * 5;
341
351
  await new Promise(resolve => setTimeout(resolve, delay));
342
- return {
352
+ return {
343
353
  id: params.id,
344
- processedAt: Date.now()
354
+ processedAt: Date.now(),
345
355
  };
346
356
  });
347
357
  });
348
358
 
349
359
  When("I make concurrent requests to {string}, {string}, and {string}", async (_, path1: string, path2: string, path3: string) => {
350
360
  const promises = [
351
- mock.handle('GET', path1),
352
- mock.handle('GET', path2),
353
- mock.handle('GET', path3)
361
+ mock.handle("GET", path1),
362
+ mock.handle("GET", path2),
363
+ mock.handle("GET", path3),
354
364
  ];
355
365
  responses = await Promise.all(promises);
356
366
  });
357
367
 
358
368
  Then("all responses should have different processedAt timestamps", () => {
359
369
  const timestamps = responses.map(r => r.body.processedAt);
360
- const uniqueTimestamps = new Set(timestamps);
361
370
  // In fast test environments, timestamps might be the same, so just check they exist
362
371
  expect(timestamps).toHaveLength(3);
363
- timestamps.forEach(timestamp => expect(timestamp).toBeGreaterThan(0));
372
+ timestamps.forEach((timestamp: number) => expect(timestamp).toBeGreaterThan(0));
364
373
  });
365
374
 
366
375
  And("each response should have the correct id value", () => {
@@ -373,39 +382,40 @@ describeFeature(feature, ({ Scenario }) => {
373
382
  // All responses should be successful regardless of timing
374
383
  for (const response of responses) {
375
384
  expect(response.status).toBe(200);
376
- expect(response.body).toHaveProperty('id');
377
- expect(response.body).toHaveProperty('processedAt');
385
+ expect(response.body).toHaveProperty("id");
386
+ expect(response.body).toHaveProperty("processedAt");
378
387
  }
379
388
  });
380
389
  });
381
390
 
382
391
  Scenario("Async plugin pipeline with context state", ({ Given, When, Then, And }) => {
383
- Given("I create a mock with async stateful plugins:", (_, docString: string) => {
392
+ Given("I create a mock with two async stateful plugins at {string}", (_, route: string) => {
393
+ const [method, path] = route.split(" ");
384
394
  mock = schmock();
385
- const plugin1 = {
386
- name: 'async-step-1',
387
- process: async (ctx: any, response: any) => {
395
+ const plugin1: Plugin = {
396
+ name: "async-step-1",
397
+ process: async (ctx, response) => {
388
398
  await new Promise(resolve => setTimeout(resolve, 5));
389
- ctx.state.set('step1', 'completed');
399
+ ctx.state.set("step1", "completed");
390
400
  return { context: ctx, response };
391
- }
401
+ },
392
402
  };
393
- const plugin2 = {
394
- name: 'async-step-2',
395
- process: async (ctx: any, response: any) => {
403
+ const plugin2: Plugin = {
404
+ name: "async-step-2",
405
+ process: async (ctx, response) => {
396
406
  await new Promise(resolve => setTimeout(resolve, 3));
397
- const step1Status = ctx.state.get('step1');
407
+ const step1Status = ctx.state.get("step1");
398
408
  return {
399
409
  context: ctx,
400
410
  response: {
401
411
  ...response,
402
412
  step1: step1Status,
403
- step2: 'completed'
404
- }
413
+ step2: "completed",
414
+ },
405
415
  };
406
- }
416
+ },
407
417
  };
408
- mock('GET /async-pipeline', { base: 'data' })
418
+ mock(`${method} ${path}` as any, { base: "data" })
409
419
  .pipe(plugin1)
410
420
  .pipe(plugin2);
411
421
  });
@@ -424,4 +434,4 @@ describeFeature(feature, ({ Scenario }) => {
424
434
  expect(response.body).toHaveProperty("step2", "completed");
425
435
  });
426
436
  });
427
- });
437
+ });
@@ -1,7 +1,7 @@
1
1
  import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
2
  import { expect } from "vitest";
3
- import { schmock } from "../index";
4
3
  import type { CallableMockInstance } from "../types";
4
+ import { schmock } from "../index";
5
5
 
6
6
  const feature = await loadFeature("../../features/basic-usage.feature");
7
7
 
@@ -10,9 +10,10 @@ describeFeature(feature, ({ Scenario }) => {
10
10
  let response: any;
11
11
 
12
12
  Scenario("Simplest possible mock - plain text", ({ Given, When, Then, And }) => {
13
- Given("I create a mock with:", (_, docString: string) => {
13
+ Given("I create a plain text mock returning {string} at {string}", (_, text: string, route: string) => {
14
+ const [method, path] = route.split(" ");
14
15
  mock = schmock();
15
- mock('GET /', 'Hello World');
16
+ mock(`${method} ${path}` as Schmock.RouteKey, text);
16
17
  });
17
18
 
18
19
  When("I request {string}", async (_, request: string) => {
@@ -30,9 +31,10 @@ describeFeature(feature, ({ Scenario }) => {
30
31
  });
31
32
 
32
33
  Scenario("Return JSON without specifying contentType", ({ Given, When, Then, And }) => {
33
- Given("I create a mock with:", (_, docString: string) => {
34
+ Given("I create a mock returning a JSON array at {string}", (_, route: string) => {
35
+ const [method, path] = route.split(" ");
34
36
  mock = schmock();
35
- mock('GET /users', [{ id: 1, name: 'John' }]);
37
+ mock(`${method} ${path}` as Schmock.RouteKey, [{ id: 1, name: "John" }]);
36
38
  });
37
39
 
38
40
  When("I request {string}", async (_, request: string) => {
@@ -51,9 +53,10 @@ describeFeature(feature, ({ Scenario }) => {
51
53
  });
52
54
 
53
55
  Scenario("Return object without contentType", ({ Given, When, Then, And }) => {
54
- Given("I create a mock with:", (_, docString: string) => {
56
+ Given("I create a mock returning a JSON object at {string}", (_, route: string) => {
57
+ const [method, path] = route.split(" ");
55
58
  mock = schmock();
56
- mock('GET /user', { id: 1, name: 'John' });
59
+ mock(`${method} ${path}` as Schmock.RouteKey, { id: 1, name: "John" });
57
60
  });
58
61
 
59
62
  When("I request {string}", async (_, request: string) => {
@@ -72,7 +75,7 @@ describeFeature(feature, ({ Scenario }) => {
72
75
  });
73
76
 
74
77
  Scenario("Empty mock instance", ({ Given, When, Then }) => {
75
- Given("I create a mock with:", (_, docString: string) => {
78
+ Given("I create an empty mock with no routes", () => {
76
79
  mock = schmock();
77
80
  });
78
81
 
@@ -87,9 +90,10 @@ describeFeature(feature, ({ Scenario }) => {
87
90
  });
88
91
 
89
92
  Scenario("Null response", ({ Given, When, Then, And }) => {
90
- Given("I create a mock with:", (_, docString: string) => {
93
+ Given("I create a mock returning null at {string}", (_, route: string) => {
94
+ const [method, path] = route.split(" ");
91
95
  mock = schmock();
92
- mock('GET /null', null);
96
+ mock(`${method} ${path}` as Schmock.RouteKey, null);
93
97
  });
94
98
 
95
99
  When("I request {string}", async (_, request: string) => {
@@ -107,9 +111,10 @@ describeFeature(feature, ({ Scenario }) => {
107
111
  });
108
112
 
109
113
  Scenario("Undefined response", ({ Given, When, Then, And }) => {
110
- Given("I create a mock with:", (_, docString: string) => {
114
+ Given("I create a mock returning undefined at {string}", (_, route: string) => {
115
+ const [method, path] = route.split(" ");
111
116
  mock = schmock();
112
- mock('GET /undefined', undefined);
117
+ mock(`${method} ${path}` as Schmock.RouteKey, undefined);
113
118
  });
114
119
 
115
120
  When("I request {string}", async (_, request: string) => {
@@ -127,9 +132,10 @@ describeFeature(feature, ({ Scenario }) => {
127
132
  });
128
133
 
129
134
  Scenario("Empty string response", ({ Given, When, Then, And }) => {
130
- Given("I create a mock with:", (_, docString: string) => {
135
+ Given("I create a mock returning empty string at {string}", (_, route: string) => {
136
+ const [method, path] = route.split(" ");
131
137
  mock = schmock();
132
- mock('GET /empty', '');
138
+ mock(`${method} ${path}` as Schmock.RouteKey, "");
133
139
  });
134
140
 
135
141
  When("I request {string}", async (_, request: string) => {
@@ -147,9 +153,10 @@ describeFeature(feature, ({ Scenario }) => {
147
153
  });
148
154
 
149
155
  Scenario("Number response", ({ Given, When, Then, And }) => {
150
- Given("I create a mock with:", (_, docString: string) => {
156
+ Given("I create a mock returning number {int} at {string}", (_, num: number, route: string) => {
157
+ const [method, path] = route.split(" ");
151
158
  mock = schmock();
152
- mock('GET /count', 42);
159
+ mock(`${method} ${path}` as Schmock.RouteKey, num);
153
160
  });
154
161
 
155
162
  When("I request {string}", async (_, request: string) => {
@@ -167,9 +174,10 @@ describeFeature(feature, ({ Scenario }) => {
167
174
  });
168
175
 
169
176
  Scenario("Boolean response", ({ Given, When, Then, And }) => {
170
- Given("I create a mock with:", (_, docString: string) => {
177
+ Given("I create a mock returning boolean true at {string}", (_, route: string) => {
178
+ const [method, path] = route.split(" ");
171
179
  mock = schmock();
172
- mock('GET /active', true);
180
+ mock(`${method} ${path}` as Schmock.RouteKey, true);
173
181
  });
174
182
 
175
183
  When("I request {string}", async (_, request: string) => {
@@ -187,9 +195,10 @@ describeFeature(feature, ({ Scenario }) => {
187
195
  });
188
196
 
189
197
  Scenario("Function returning string", ({ Given, When, Then }) => {
190
- Given("I create a mock with:", (_, docString: string) => {
198
+ Given("I create a mock with a string generator at {string}", (_, route: string) => {
199
+ const [method, path] = route.split(" ");
191
200
  mock = schmock();
192
- mock('GET /dynamic', () => 'Dynamic response');
201
+ mock(`${method} ${path}` as Schmock.RouteKey, () => "Dynamic response");
193
202
  });
194
203
 
195
204
  When("I request {string}", async (_, request: string) => {
@@ -203,9 +212,10 @@ describeFeature(feature, ({ Scenario }) => {
203
212
  });
204
213
 
205
214
  Scenario("Function returning object", ({ Given, When, Then, And }) => {
206
- Given("I create a mock with:", (_, docString: string) => {
215
+ Given("I create a mock with an object generator at {string}", (_, route: string) => {
216
+ const [method, path] = route.split(" ");
207
217
  mock = schmock();
208
- mock('GET /dynamic-json', () => ({ timestamp: Date.now() }));
218
+ mock(`${method} ${path}` as Schmock.RouteKey, () => ({ timestamp: Date.now() }));
209
219
  });
210
220
 
211
221
  When("I request {string}", async (_, request: string) => {
@@ -227,17 +237,17 @@ describeFeature(feature, ({ Scenario }) => {
227
237
  let aboutResponse: any;
228
238
  let contactResponse: any;
229
239
 
230
- Given("I create a mock with:", (_, docString: string) => {
240
+ Given("I create a mock with three routes", () => {
231
241
  mock = schmock();
232
- mock('GET /', 'Home');
233
- mock('GET /about', 'About Us');
234
- mock('GET /contact', { email: 'test@example.com' });
242
+ mock("GET /", "Home");
243
+ mock("GET /about", "About Us");
244
+ mock("GET /contact", { email: "test@example.com" });
235
245
  });
236
246
 
237
247
  When("I make three requests to different routes", async () => {
238
- homeResponse = await mock.handle('GET', '/');
239
- aboutResponse = await mock.handle('GET', '/about');
240
- contactResponse = await mock.handle('GET', '/contact');
248
+ homeResponse = await mock.handle("GET", "/");
249
+ aboutResponse = await mock.handle("GET", "/about");
250
+ contactResponse = await mock.handle("GET", "/contact");
241
251
  });
242
252
 
243
253
  Then("the home route should return {string}", (_, expectedText: string) => {
@@ -255,9 +265,10 @@ describeFeature(feature, ({ Scenario }) => {
255
265
  });
256
266
 
257
267
  Scenario("Override contentType detection", ({ Given, When, Then, And }) => {
258
- Given("I create a mock with:", (_, docString: string) => {
268
+ Given("I create a mock with explicit text/plain contentType at {string}", (_, route: string) => {
269
+ const [method, path] = route.split(" ");
259
270
  mock = schmock();
260
- mock('GET /data', { foo: 'bar' }, { contentType: 'text/plain' });
271
+ mock(`${method} ${path}` as Schmock.RouteKey, { foo: "bar" }, { contentType: "text/plain" });
261
272
  });
262
273
 
263
274
  When("I request {string}", async (_, request: string) => {
@@ -275,9 +286,10 @@ describeFeature(feature, ({ Scenario }) => {
275
286
  });
276
287
 
277
288
  Scenario("HTML response", ({ Given, When, Then, And }) => {
278
- Given("I create a mock with:", (_, docString: string) => {
289
+ Given("I create a mock returning HTML at {string}", (_, route: string) => {
290
+ const [method, path] = route.split(" ");
279
291
  mock = schmock();
280
- mock('GET /page', '<h1>Hello</h1>', { contentType: 'text/html' });
292
+ mock(`${method} ${path}` as Schmock.RouteKey, "<h1>Hello</h1>", { contentType: "text/html" });
281
293
  });
282
294
 
283
295
  When("I request {string}", async (_, request: string) => {
@@ -295,9 +307,10 @@ describeFeature(feature, ({ Scenario }) => {
295
307
  });
296
308
 
297
309
  Scenario("Binary/buffer response detection", ({ Given, When, Then, And }) => {
298
- Given("I create a mock with:", (_, docString: string) => {
310
+ Given("I create a mock returning a Buffer at {string}", (_, route: string) => {
311
+ const [method, path] = route.split(" ");
299
312
  mock = schmock();
300
- mock('GET /binary', Buffer.from('binary data'));
313
+ mock(`${method} ${path}` as Schmock.RouteKey, Buffer.from("binary data") as unknown as Schmock.Generator);
301
314
  });
302
315
 
303
316
  When("I request {string}", async (_, request: string) => {
@@ -313,4 +326,4 @@ describeFeature(feature, ({ Scenario }) => {
313
326
  expect(response.headers?.["content-type"]).toBe(contentType);
314
327
  });
315
328
  });
316
- });
329
+ });