@schmock/core 2.3.0 → 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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/dist/abort.d.ts +3 -0
  4. package/dist/abort.d.ts.map +1 -0
  5. package/dist/abort.js +30 -0
  6. package/dist/builder.d.ts +31 -10
  7. package/dist/builder.d.ts.map +1 -1
  8. package/dist/builder.js +760 -190
  9. package/dist/constants.d.ts +38 -0
  10. package/dist/constants.d.ts.map +1 -1
  11. package/dist/constants.js +123 -2
  12. package/dist/errors.d.ts +14 -3
  13. package/dist/errors.d.ts.map +1 -1
  14. package/dist/errors.js +41 -6
  15. package/dist/helpers.d.ts +9 -0
  16. package/dist/helpers.d.ts.map +1 -1
  17. package/dist/helpers.js +18 -2
  18. package/dist/http-helpers.d.ts +39 -4
  19. package/dist/http-helpers.d.ts.map +1 -1
  20. package/dist/http-helpers.js +147 -49
  21. package/dist/index.d.ts +292 -34
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +8 -3
  24. package/dist/interceptor.d.ts +11 -1
  25. package/dist/interceptor.d.ts.map +1 -1
  26. package/dist/interceptor.js +316 -169
  27. package/dist/parser.d.ts.map +1 -1
  28. package/dist/parser.js +12 -3
  29. package/dist/plugin-pipeline.d.ts +3 -3
  30. package/dist/plugin-pipeline.d.ts.map +1 -1
  31. package/dist/plugin-pipeline.js +29 -14
  32. package/dist/response-normalizer.d.ts +16 -0
  33. package/dist/response-normalizer.d.ts.map +1 -0
  34. package/dist/response-normalizer.js +316 -0
  35. package/dist/response-parser.d.ts.map +1 -1
  36. package/dist/response-parser.js +39 -2
  37. package/dist/route-matcher.d.ts +3 -0
  38. package/dist/route-matcher.d.ts.map +1 -1
  39. package/dist/route-matcher.js +12 -6
  40. package/dist/types.d.ts +7 -2
  41. package/dist/types.d.ts.map +1 -1
  42. package/package.json +14 -6
  43. package/src/audit-core-builder.test.ts +0 -218
  44. package/src/audit-response-guard.test.ts +0 -38
  45. package/src/binary.test.ts +0 -126
  46. package/src/binary.ts +0 -11
  47. package/src/builder.test.ts +0 -289
  48. package/src/builder.ts +0 -748
  49. package/src/constants.test.ts +0 -99
  50. package/src/constants.ts +0 -73
  51. package/src/debug.test.ts +0 -241
  52. package/src/delay.test.ts +0 -319
  53. package/src/dist-shape.test.ts +0 -35
  54. package/src/errors.test.ts +0 -223
  55. package/src/errors.ts +0 -130
  56. package/src/factory.test.ts +0 -133
  57. package/src/helpers.test.ts +0 -147
  58. package/src/helpers.ts +0 -58
  59. package/src/http-helpers.test.ts +0 -39
  60. package/src/http-helpers.ts +0 -149
  61. package/src/index.ts +0 -152
  62. package/src/interceptor.test.ts +0 -488
  63. package/src/interceptor.ts +0 -407
  64. package/src/namespace.test.ts +0 -274
  65. package/src/parser.property.test.ts +0 -630
  66. package/src/parser.test.ts +0 -148
  67. package/src/parser.ts +0 -64
  68. package/src/plugin-pipeline.ts +0 -208
  69. package/src/plugin-system.test.ts +0 -697
  70. package/src/response-parser.ts +0 -114
  71. package/src/response-parsing.test.ts +0 -333
  72. package/src/route-matcher.ts +0 -69
  73. package/src/route-matching.test.ts +0 -394
  74. package/src/server.test.ts +0 -234
  75. package/src/smart-defaults.test.ts +0 -361
  76. package/src/steps/async-support.steps.ts +0 -421
  77. package/src/steps/audit-core-builder.steps.ts +0 -188
  78. package/src/steps/audit-onerror-tuple.steps.ts +0 -83
  79. package/src/steps/basic-usage.steps.ts +0 -245
  80. package/src/steps/developer-experience.steps.ts +0 -204
  81. package/src/steps/error-handling.steps.ts +0 -555
  82. package/src/steps/fetch-interceptor.steps.ts +0 -457
  83. package/src/steps/fluent-api.steps.ts +0 -255
  84. package/src/steps/http-methods.steps.ts +0 -342
  85. package/src/steps/lifecycle-events.steps.ts +0 -149
  86. package/src/steps/performance-reliability.steps.ts +0 -90
  87. package/src/steps/plugin-integration.steps.ts +0 -334
  88. package/src/steps/request-history.steps.ts +0 -458
  89. package/src/steps/response-delay.steps.ts +0 -88
  90. package/src/steps/route-key-format.steps.ts +0 -99
  91. package/src/steps/standalone-server.steps.ts +0 -227
  92. package/src/steps/state-concurrency.steps.ts +0 -167
  93. package/src/types.ts +0 -36
@@ -1,458 +0,0 @@
1
- import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
- import { expect } from "vitest";
3
- import { schmock, toHttpMethod } from "../index";
4
- import type { CallableMockInstance } from "../types";
5
-
6
- const feature = await loadFeature("../../features/request-history.feature");
7
-
8
- interface HistoryTableRow {
9
- field: string;
10
- value: string;
11
- }
12
-
13
- function parseRequest(request: string): {
14
- method: Schmock.HttpMethod;
15
- path: string;
16
- } {
17
- const separator = request.indexOf(" ");
18
- const methodText = request.slice(0, separator);
19
- const path = request.slice(separator + 1);
20
- if (separator <= 0 || !path.startsWith("/")) {
21
- throw new Error(`Expected request in METHOD /path format, got: ${request}`);
22
- }
23
- return { method: toHttpMethod(methodText), path };
24
- }
25
-
26
- function requireRecord(
27
- value: unknown,
28
- description: string,
29
- ): Record<string, unknown> {
30
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
31
- throw new Error(`Expected ${description} to be an object`);
32
- }
33
- return Object.fromEntries(Object.entries(value));
34
- }
35
-
36
- function requireStringRecord(
37
- value: unknown,
38
- description: string,
39
- ): Record<string, string> {
40
- const record = requireRecord(value, description);
41
- const strings: Record<string, string> = {};
42
- for (const [key, entry] of Object.entries(record)) {
43
- if (typeof entry !== "string") {
44
- throw new Error(`Expected ${description}.${key} to be a string`);
45
- }
46
- strings[key] = entry;
47
- }
48
- return strings;
49
- }
50
-
51
- function parseJson(docString: string): unknown {
52
- const parsed: unknown = JSON.parse(docString);
53
- return parsed;
54
- }
55
-
56
- function parseRequestOptions(docString: string): Schmock.RequestOptions {
57
- const parsed = requireRecord(parseJson(docString), "request options");
58
- const options: Schmock.RequestOptions = {};
59
- if (parsed.headers !== undefined) {
60
- options.headers = requireStringRecord(parsed.headers, "request headers");
61
- }
62
- if (parsed.query !== undefined) {
63
- options.query = requireStringRecord(parsed.query, "request query");
64
- }
65
- if ("body" in parsed) {
66
- options.body = parsed.body;
67
- }
68
- return options;
69
- }
70
-
71
- function requireHistoryTable(table: unknown): HistoryTableRow[] {
72
- if (!Array.isArray(table)) {
73
- throw new Error("Expected request history table rows");
74
- }
75
- return table.map((candidate) => {
76
- const row = requireRecord(candidate, "request history table row");
77
- if (typeof row.field !== "string" || typeof row.value !== "string") {
78
- throw new Error("Expected request history table field and value strings");
79
- }
80
- return { field: row.field, value: row.value };
81
- });
82
- }
83
-
84
- function requestRecordField(
85
- record: Schmock.RequestRecord,
86
- field: string,
87
- ): unknown {
88
- switch (field) {
89
- case "method":
90
- return record.method;
91
- case "path":
92
- return record.path;
93
- case "params":
94
- return record.params;
95
- case "query":
96
- return record.query;
97
- case "headers":
98
- return record.headers;
99
- case "body":
100
- return record.body;
101
- case "timestamp":
102
- return record.timestamp;
103
- case "response":
104
- return record.response;
105
- default:
106
- throw new Error(`Unknown request record field: ${field}`);
107
- }
108
- }
109
-
110
- describeFeature(feature, ({ Scenario }) => {
111
- let mock: CallableMockInstance;
112
- let response: Schmock.Response;
113
-
114
- Scenario("Record multiple requests", ({ Given, When, And, Then }) => {
115
- Given("I create a mock with GET and POST user routes", () => {
116
- mock = schmock();
117
- mock("GET /users", [{ id: 1 }]);
118
- mock("POST /users", ({ body }) => [201, body]);
119
- });
120
-
121
- When("I request {string}", async (_, request: string) => {
122
- const { method, path } = parseRequest(request);
123
- response = await mock.handle(method, path);
124
- });
125
-
126
- And(
127
- "I request {string} with body:",
128
- async (_, request: string, docString: string) => {
129
- const { method, path } = parseRequest(request);
130
- const body = parseJson(docString);
131
- response = await mock.handle(method, path, { body });
132
- },
133
- );
134
-
135
- And("I request {string}", async (_, request: string) => {
136
- const { method, path } = parseRequest(request);
137
- response = await mock.handle(method, path);
138
- });
139
-
140
- Then("the call count should be 3", () => {
141
- expect(mock.callCount()).toBe(3);
142
- });
143
-
144
- And(
145
- "the call count for {string} should be {int}",
146
- (_, route: string, count: number) => {
147
- const { method, path } = parseRequest(route);
148
- expect(mock.callCount(method, path)).toBe(count);
149
- },
150
- );
151
-
152
- And(
153
- "the call count for {string} should be {int} request",
154
- (_, route: string, count: number) => {
155
- const { method, path } = parseRequest(route);
156
- expect(mock.callCount(method, path)).toBe(count);
157
- },
158
- );
159
- });
160
-
161
- Scenario(
162
- "Filter history by method and path",
163
- ({ Given, When, And, Then }) => {
164
- Given("I create a mock with users and posts routes", () => {
165
- mock = schmock();
166
- mock("GET /users", []);
167
- mock("POST /users", ({ body }) => [201, body]);
168
- mock("GET /posts", []);
169
- });
170
-
171
- When("I request {string}", async (_, request: string) => {
172
- const { method, path } = parseRequest(request);
173
- response = await mock.handle(method, path);
174
- });
175
-
176
- And(
177
- "I request {string} with body:",
178
- async (_, request: string, docString: string) => {
179
- const { method, path } = parseRequest(request);
180
- const body = parseJson(docString);
181
- response = await mock.handle(method, path, { body });
182
- },
183
- );
184
-
185
- And("I request {string}", async (_, request: string) => {
186
- const { method, path } = parseRequest(request);
187
- response = await mock.handle(method, path);
188
- });
189
-
190
- Then(
191
- "the history for {string} should have {int} record",
192
- (_, route: string, count: number) => {
193
- const { method, path } = parseRequest(route);
194
- expect(mock.history(method, path)).toHaveLength(count);
195
- },
196
- );
197
-
198
- And(
199
- "the history for {string} should have {int} record",
200
- (_, route: string, count: number) => {
201
- const { method, path } = parseRequest(route);
202
- expect(mock.history(method, path)).toHaveLength(count);
203
- },
204
- );
205
-
206
- And(
207
- "the history for {string} should have {int} entry",
208
- (_, route: string, count: number) => {
209
- const { method, path } = parseRequest(route);
210
- expect(mock.history(method, path)).toHaveLength(count);
211
- },
212
- );
213
-
214
- And(
215
- "the history for {string} should have {int} entries",
216
- (_, route: string, count: number) => {
217
- const { method, path } = parseRequest(route);
218
- expect(mock.history(method, path)).toHaveLength(count);
219
- },
220
- );
221
- },
222
- );
223
-
224
- Scenario(
225
- "Check if specific route was called",
226
- ({ Given, When, Then, And }) => {
227
- Given("I create a mock with users and posts list routes", () => {
228
- mock = schmock();
229
- mock("GET /users", []);
230
- mock("GET /posts", []);
231
- });
232
-
233
- When("I request {string}", async (_, request: string) => {
234
- const { method, path } = parseRequest(request);
235
- response = await mock.handle(method, path);
236
- });
237
-
238
- Then("{string} should have been called", (_, route: string) => {
239
- const { method, path } = parseRequest(route);
240
- expect(mock.called(method, path)).toBe(true);
241
- });
242
-
243
- And("{string} should not have been called", (_, route: string) => {
244
- const { method, path } = parseRequest(route);
245
- expect(mock.called(method, path)).toBe(false);
246
- });
247
- },
248
- );
249
-
250
- Scenario(
251
- "Request record captures full details",
252
- ({ Given, When, Then, And }) => {
253
- Given("I create a mock with a parameterized POST route", () => {
254
- mock = schmock();
255
- mock("POST /users/:id", ({ params, body }) => {
256
- const requestBody = requireRecord(body, "request body");
257
- return [200, { ...requestBody, id: params.id }];
258
- });
259
- });
260
-
261
- When(
262
- "I request {string} with headers and body:",
263
- async (_, request: string, docString: string) => {
264
- const { method, path } = parseRequest(request);
265
- const options = parseRequestOptions(docString);
266
- response = await mock.handle(method, path, options);
267
- },
268
- );
269
-
270
- Then("the last request should have:", (_, table: unknown) => {
271
- const record = mock.lastRequest();
272
- if (!record) {
273
- throw new Error("Expected a recorded request");
274
- }
275
- for (const row of requireHistoryTable(table)) {
276
- expect(requestRecordField(record, row.field)).toBe(row.value);
277
- }
278
- });
279
-
280
- And(
281
- "the last request params should include {string} = {string}",
282
- (_, key: string, value: string) => {
283
- expect(mock.lastRequest()?.params[key]).toBe(value);
284
- },
285
- );
286
-
287
- And(
288
- "the last request headers should include {string} = {string}",
289
- (_, key: string, value: string) => {
290
- expect(mock.lastRequest()?.headers[key]).toBe(value);
291
- },
292
- );
293
-
294
- And(
295
- "the last request body should have property {string} with value {string}",
296
- (_, prop: string, value: string) => {
297
- const record = mock.lastRequest();
298
- if (!record) {
299
- throw new Error("Expected a recorded request");
300
- }
301
- expect(requireRecord(record.body, "request body")[prop]).toBe(value);
302
- },
303
- );
304
-
305
- And("the last request should have a timestamp", () => {
306
- const record = mock.lastRequest();
307
- if (!record) {
308
- throw new Error("Expected a recorded request");
309
- }
310
- expect(typeof record.timestamp).toBe("number");
311
- expect(record.timestamp).toBeGreaterThan(0);
312
- });
313
-
314
- And(
315
- "the last request response status should be {int}",
316
- (_, status: number) => {
317
- expect(mock.lastRequest()?.response.status).toBe(status);
318
- },
319
- );
320
- },
321
- );
322
-
323
- Scenario(
324
- "Get last request for a specific route",
325
- ({ Given, When, And, Then }) => {
326
- Given(
327
- "I create a mock echoing POST body at {string}",
328
- (_, path: string) => {
329
- mock = schmock();
330
- mock(`POST ${path}`, ({ body }) => [201, body]);
331
- },
332
- );
333
-
334
- When(
335
- "I request {string} with body:",
336
- async (_, request: string, docString: string) => {
337
- const { method, path } = parseRequest(request);
338
- const body = parseJson(docString);
339
- response = await mock.handle(method, path, { body });
340
- },
341
- );
342
-
343
- And(
344
- "I request {string} with body:",
345
- async (_, request: string, docString: string) => {
346
- const { method, path } = parseRequest(request);
347
- const body = parseJson(docString);
348
- response = await mock.handle(method, path, { body });
349
- },
350
- );
351
-
352
- Then(
353
- "the last request for {string} body should have property {string} with value {string}",
354
- (_, route: string, prop: string, value: string) => {
355
- const { method, path } = parseRequest(route);
356
- const record = mock.lastRequest(method, path);
357
- if (!record) {
358
- throw new Error(`Expected a recorded request for ${route}`);
359
- }
360
- expect(requireRecord(record.body, "request body")[prop]).toBe(value);
361
- },
362
- );
363
- },
364
- );
365
-
366
- Scenario(
367
- "404 requests are not recorded in history",
368
- ({ Given, When, Then, And }) => {
369
- Given("I create a mock with only a users route", () => {
370
- mock = schmock();
371
- mock("GET /users", []);
372
- });
373
-
374
- When("I request {string}", async (_, request: string) => {
375
- const { method, path } = parseRequest(request);
376
- response = await mock.handle(method, path);
377
- });
378
-
379
- Then("the mock should not have been called", () => {
380
- expect(mock.called()).toBe(false);
381
- });
382
-
383
- And("the call count should be 0", () => {
384
- expect(mock.callCount()).toBe(0);
385
- });
386
- },
387
- );
388
-
389
- Scenario(
390
- "maxHistorySize bounds the history with FIFO eviction",
391
- ({ Given, When, Then, And }) => {
392
- Given(
393
- "I create a mock with maxHistorySize {int} and a users route",
394
- (_, maxHistorySize: number) => {
395
- mock = schmock({ maxHistorySize });
396
- mock("GET /users", []);
397
- },
398
- );
399
-
400
- When(
401
- "I issue {int} sequenced requests to {string}",
402
- async (_, count: number, request: string) => {
403
- const { method, path } = parseRequest(request);
404
- for (let i = 0; i < count; i++) {
405
- await mock.handle(method, path, {
406
- query: { sequence: String(i + 1) },
407
- });
408
- }
409
- },
410
- );
411
-
412
- Then("the call count should be {int}", (_, expected: number) => {
413
- expect(mock.callCount()).toBe(expected);
414
- });
415
-
416
- And(
417
- "the retained request sequence should be {string}",
418
- (_, sequence: string) => {
419
- expect(mock.history().map((record) => record.query.sequence)).toEqual(
420
- sequence.split(","),
421
- );
422
- },
423
- );
424
- },
425
- );
426
-
427
- Scenario(
428
- "Resetting history preserves routes and shared state",
429
- ({ Given, When, Then, And }) => {
430
- Given("I create a stateful mock and record a request", async () => {
431
- mock = schmock({ state: { marker: "preserved" } });
432
- mock("GET /stateful", ({ state }) => ({ marker: state.marker }));
433
- await mock.handle("GET", "/stateful");
434
- expect(mock.callCount()).toBe(1);
435
- });
436
-
437
- When("I reset only the request history", () => {
438
- mock.resetHistory();
439
- });
440
-
441
- Then("the call count should be {int}", (_, expected: number) => {
442
- expect(mock.callCount()).toBe(expected);
443
- });
444
-
445
- And("the registered route should still respond", async () => {
446
- response = await mock.handle("GET", "/stateful");
447
- expect(response.status).toBe(200);
448
- });
449
-
450
- And(
451
- "the shared state marker should still be {string}",
452
- (_, marker: string) => {
453
- expect(mock.getState().marker).toBe(marker);
454
- },
455
- );
456
- },
457
- );
458
- });
@@ -1,88 +0,0 @@
1
- import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
- import { expect } from "vitest";
3
- import { schmock } from "../index";
4
-
5
- const feature = await loadFeature("../../features/response-delay.feature");
6
-
7
- describeFeature(feature, ({ Scenario }) => {
8
- let mock: Schmock.CallableMockInstance;
9
- let elapsed: number;
10
- let elapsed2: number;
11
-
12
- Scenario("Route delay overrides global delay", ({ Given, And, When, Then }) => {
13
- Given("a mock with global delay of 200ms", () => {
14
- mock = schmock({ delay: 200, state: {} });
15
- });
16
-
17
- And('a route "GET /fast" with delay of 10ms', () => {
18
- mock("GET /fast", { ok: true }, { delay: 10 });
19
- });
20
-
21
- And('a route "GET /default" with no delay override', () => {
22
- mock("GET /default", { ok: true }, {});
23
- });
24
-
25
- When('I request "GET /fast"', async () => {
26
- const start = performance.now();
27
- await mock.handle("GET", "/fast");
28
- elapsed = performance.now() - start;
29
- });
30
-
31
- // Upper bound is intentionally generous: it only needs to prove the 10ms
32
- // route delay was used instead of the 200ms global. A tight bound here
33
- // flakes under CI load (a single timer can be delayed tens of ms).
34
- Then("the response took less than 150ms", () => {
35
- expect(elapsed).toBeLessThan(150);
36
- });
37
-
38
- When('I request "GET /default" with timing', async () => {
39
- const start = performance.now();
40
- await mock.handle("GET", "/default");
41
- elapsed2 = performance.now() - start;
42
- });
43
-
44
- Then("that response took at least 150ms", () => {
45
- expect(elapsed2).toBeGreaterThanOrEqual(150);
46
- });
47
- });
48
-
49
- Scenario("Route delay supports random range", ({ Given, And, When, Then }) => {
50
- Given("a mock with no global delay", () => {
51
- mock = schmock({ state: {} });
52
- });
53
-
54
- And('a route "GET /random" with delay range 10 to 30', () => {
55
- mock("GET /random", { ok: true }, { delay: [10, 30] });
56
- });
57
-
58
- When('I request "GET /random"', async () => {
59
- const start = performance.now();
60
- await mock.handle("GET", "/random");
61
- elapsed = performance.now() - start;
62
- });
63
-
64
- Then("the response took at least 8ms", () => {
65
- expect(elapsed).toBeGreaterThanOrEqual(8);
66
- });
67
- });
68
-
69
- Scenario("No route delay inherits global delay", ({ Given, And, When, Then }) => {
70
- Given("a mock with global delay of 50ms", () => {
71
- mock = schmock({ delay: 50, state: {} });
72
- });
73
-
74
- And('a route "GET /items" with no delay override', () => {
75
- mock("GET /items", { ok: true }, {});
76
- });
77
-
78
- When('I request "GET /items" with timing', async () => {
79
- const start = performance.now();
80
- await mock.handle("GET", "/items");
81
- elapsed = performance.now() - start;
82
- });
83
-
84
- Then("that response took at least 40ms", () => {
85
- expect(elapsed).toBeGreaterThanOrEqual(40);
86
- });
87
- });
88
- });
@@ -1,99 +0,0 @@
1
- import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
- import { expect } from "vitest";
3
- import type { ParsedRoute } from "../parser";
4
- import { parseRouteKey } from "../parser";
5
-
6
- const feature = await loadFeature("../../features/route-key-format.feature");
7
-
8
- describeFeature(feature, ({ Scenario, ScenarioOutline }) => {
9
- let result: ParsedRoute;
10
- let error: Error | null = null;
11
-
12
- ScenarioOutline(
13
- "Valid route key formats",
14
- ({ When, Then, And }, variables) => {
15
- When("I parse route key {string}", () => {
16
- error = null;
17
- try {
18
- result = parseRouteKey(variables.key);
19
- } catch (e) {
20
- error = e as Error;
21
- }
22
- });
23
-
24
- Then("the method should be {string}", () => {
25
- expect(error).toBeNull();
26
- expect(result.method).toBe(variables.method);
27
- });
28
-
29
- And("the path should be {string}", () => {
30
- expect(result.path).toBe(variables.path);
31
- });
32
- },
33
- );
34
-
35
- ScenarioOutline("Invalid route key formats", ({ When, Then }, variables) => {
36
- When("I parse route key {string}", () => {
37
- error = null;
38
- try {
39
- result = parseRouteKey(variables.key);
40
- } catch (e) {
41
- error = e as Error;
42
- }
43
- });
44
-
45
- Then("an error should be thrown with message matching {string}", () => {
46
- expect(error).not.toBeNull();
47
- expect(error!.message).toMatch(variables.error);
48
- });
49
- });
50
-
51
- Scenario("Extract parameters from path", ({ When, Then, And }) => {
52
- When("I parse route key {string}", (_, routeKey: string) => {
53
- result = parseRouteKey(routeKey);
54
- });
55
-
56
- Then("the method should be {string}", (_, expectedMethod: string) => {
57
- expect(result.method).toBe(expectedMethod);
58
- });
59
-
60
- And("the path should be {string}", (_, expectedPath: string) => {
61
- expect(result.path).toBe(expectedPath);
62
- });
63
-
64
- And("the parameters should be:", (_, docString: string) => {
65
- const expectedParams = JSON.parse(docString);
66
- expect(result.params).toEqual(expectedParams);
67
- });
68
- });
69
-
70
- Scenario("No parameters in simple path", ({ When, Then }) => {
71
- When("I parse route key {string}", (_, routeKey: string) => {
72
- result = parseRouteKey(routeKey);
73
- });
74
-
75
- Then("the parameters should be:", (_, docString: string) => {
76
- const expectedParams = JSON.parse(docString);
77
- expect(result.params).toEqual(expectedParams);
78
- });
79
- });
80
-
81
- Scenario("Complex nested paths", ({ When, Then, And }) => {
82
- When("I parse route key {string}", (_, routeKey: string) => {
83
- result = parseRouteKey(routeKey);
84
- });
85
-
86
- Then("the method should be {string}", (_, expectedMethod: string) => {
87
- expect(result.method).toBe(expectedMethod);
88
- });
89
-
90
- And("the path should be {string}", (_, expectedPath: string) => {
91
- expect(result.path).toBe(expectedPath);
92
- });
93
-
94
- And("the parameters should be:", (_, docString: string) => {
95
- const expectedParams = JSON.parse(docString);
96
- expect(result.params).toEqual(expectedParams);
97
- });
98
- });
99
- });