@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.
Files changed (94) 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/binary.d.ts +8 -0
  7. package/dist/binary.d.ts.map +1 -0
  8. package/dist/binary.js +9 -0
  9. package/dist/builder.d.ts +31 -10
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/builder.js +804 -203
  12. package/dist/constants.d.ts +38 -0
  13. package/dist/constants.d.ts.map +1 -1
  14. package/dist/constants.js +123 -2
  15. package/dist/errors.d.ts +14 -3
  16. package/dist/errors.d.ts.map +1 -1
  17. package/dist/errors.js +41 -6
  18. package/dist/helpers.d.ts +9 -0
  19. package/dist/helpers.d.ts.map +1 -1
  20. package/dist/helpers.js +18 -2
  21. package/dist/http-helpers.d.ts +52 -5
  22. package/dist/http-helpers.d.ts.map +1 -1
  23. package/dist/http-helpers.js +153 -37
  24. package/dist/index.d.ts +381 -60
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +9 -3
  27. package/dist/interceptor.d.ts +11 -1
  28. package/dist/interceptor.d.ts.map +1 -1
  29. package/dist/interceptor.js +354 -156
  30. package/dist/parser.d.ts.map +1 -1
  31. package/dist/parser.js +12 -3
  32. package/dist/plugin-pipeline.d.ts +11 -4
  33. package/dist/plugin-pipeline.d.ts.map +1 -1
  34. package/dist/plugin-pipeline.js +117 -39
  35. package/dist/response-normalizer.d.ts +16 -0
  36. package/dist/response-normalizer.d.ts.map +1 -0
  37. package/dist/response-normalizer.js +316 -0
  38. package/dist/response-parser.d.ts.map +1 -1
  39. package/dist/response-parser.js +85 -18
  40. package/dist/route-matcher.d.ts +3 -0
  41. package/dist/route-matcher.d.ts.map +1 -1
  42. package/dist/route-matcher.js +12 -6
  43. package/dist/types.d.ts +7 -2
  44. package/dist/types.d.ts.map +1 -1
  45. package/package.json +18 -8
  46. package/src/audit-core-builder.test.ts +0 -218
  47. package/src/audit-response-guard.test.ts +0 -38
  48. package/src/builder.test.ts +0 -289
  49. package/src/builder.ts +0 -701
  50. package/src/constants.test.ts +0 -99
  51. package/src/constants.ts +0 -73
  52. package/src/debug.test.ts +0 -241
  53. package/src/delay.test.ts +0 -319
  54. package/src/dist-shape.test.ts +0 -35
  55. package/src/errors.test.ts +0 -223
  56. package/src/errors.ts +0 -130
  57. package/src/factory.test.ts +0 -133
  58. package/src/helpers.test.ts +0 -147
  59. package/src/helpers.ts +0 -58
  60. package/src/http-helpers.ts +0 -113
  61. package/src/index.ts +0 -151
  62. package/src/interceptor.test.ts +0 -291
  63. package/src/interceptor.ts +0 -320
  64. package/src/namespace.test.ts +0 -274
  65. package/src/parser.property.test.ts +0 -594
  66. package/src/parser.test.ts +0 -148
  67. package/src/parser.ts +0 -64
  68. package/src/plugin-pipeline.ts +0 -103
  69. package/src/plugin-system.test.ts +0 -602
  70. package/src/response-parser.ts +0 -75
  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 -165
  75. package/src/smart-defaults.test.ts +0 -361
  76. package/src/steps/async-support.steps.ts +0 -400
  77. package/src/steps/audit-core-builder.steps.ts +0 -188
  78. package/src/steps/audit-onerror-tuple.steps.ts +0 -99
  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 -345
  82. package/src/steps/fluent-api.steps.ts +0 -255
  83. package/src/steps/http-methods.steps.ts +0 -331
  84. package/src/steps/interceptor.steps.ts +0 -260
  85. package/src/steps/lifecycle-events.steps.ts +0 -142
  86. package/src/steps/performance-reliability.steps.ts +0 -423
  87. package/src/steps/plugin-integration.steps.ts +0 -280
  88. package/src/steps/request-history.steps.ts +0 -276
  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 -233
  92. package/src/steps/state-concurrency.steps.ts +0 -739
  93. package/src/steps/stateful-workflows.steps.ts +0 -353
  94. package/src/types.ts +0 -36
@@ -1,280 +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/plugin-integration.feature");
7
-
8
- describeFeature(feature, ({ Scenario }) => {
9
- let mock: CallableMockInstance;
10
- let requestResponses: any[] = [];
11
-
12
- Scenario("Plugin state sharing with pipeline", ({ Given, When, Then, And }) => {
13
- requestResponses = [];
14
-
15
- Given("I create a mock with a counter plugin using route state", () => {
16
- mock = schmock({ state: {} });
17
- mock("GET /counter", null, { contentType: "application/json" }).pipe({
18
- name: "counter-plugin",
19
- process: (ctx, response) => {
20
- const routeState = ctx.routeState!;
21
- routeState.request_count =
22
- ((routeState.request_count as number) || 0) + 1;
23
-
24
- if (!response) {
25
- return {
26
- context: ctx,
27
- response: {
28
- request_number: routeState.request_count,
29
- path: ctx.path,
30
- processed_at: new Date().toISOString(),
31
- },
32
- };
33
- }
34
-
35
- return { context: ctx, response };
36
- },
37
- });
38
- });
39
-
40
- When("I request {string} three times", async (_, request: string) => {
41
- const [method, path] = request.split(" ");
42
- requestResponses = [];
43
-
44
- for (let i = 0; i < 3; i++) {
45
- const response = await mock.handle(method as any, path);
46
- requestResponses.push(response);
47
- }
48
- });
49
-
50
- Then(
51
- "each response should have incrementing {string} values",
52
- (_, property: string) => {
53
- expect(requestResponses).toHaveLength(3);
54
-
55
- for (let i = 0; i < requestResponses.length; i++) {
56
- expect(requestResponses[i].body[property]).toBe(i + 1);
57
- }
58
- },
59
- );
60
-
61
- And(
62
- "each response should have a {string} timestamp",
63
- (_, property: string) => {
64
- for (const response of requestResponses) {
65
- expect(response.body[property]).toBeDefined();
66
- expect(typeof response.body[property]).toBe("string");
67
- expect(new Date(response.body[property]).getTime()).toBeGreaterThan(0);
68
- }
69
- },
70
- );
71
-
72
- And("the route state should persist across requests", () => {
73
- const requestNumbers = requestResponses.map(
74
- (r) => r.body.request_number,
75
- );
76
- expect(requestNumbers).toEqual([1, 2, 3]);
77
- });
78
- });
79
-
80
- Scenario("Multiple plugins in pipeline", ({ Given, When, Then }) => {
81
- Given("I create a mock with auth and wrapper plugins", () => {
82
- mock = schmock({});
83
- mock("GET /users", () => [{ id: 1, name: "John" }], {
84
- contentType: "application/json",
85
- })
86
- .pipe({
87
- name: "auth-plugin",
88
- process: (ctx, response) => {
89
- if (!ctx.headers.authorization) {
90
- throw new Error("Missing authorization");
91
- }
92
- ctx.state.set("user", { id: 1, name: "Admin" });
93
- return { context: ctx, response };
94
- },
95
- })
96
- .pipe({
97
- name: "wrapper-plugin",
98
- process: (ctx, response) => {
99
- if (response) {
100
- return {
101
- context: ctx,
102
- response: {
103
- data: response,
104
- meta: {
105
- user: ctx.state.get("user"),
106
- timestamp: "2025-01-31T10:15:30.123Z",
107
- },
108
- },
109
- };
110
- }
111
- return { context: ctx, response };
112
- },
113
- });
114
- });
115
-
116
- When(
117
- "I request {string} with headers:",
118
- async (_, request: string, docString: string) => {
119
- const [method, path] = request.split(" ");
120
- const headers = JSON.parse(docString);
121
- requestResponses = [
122
- await mock.handle(method as any, path, { headers }),
123
- ];
124
- },
125
- );
126
-
127
- Then("I should receive:", (_, docString: string) => {
128
- const expected = JSON.parse(docString);
129
- expect(requestResponses[0].body).toEqual(expected);
130
- });
131
- });
132
-
133
- Scenario("Plugin error handling", ({ Given, When, Then, And }) => {
134
- Given("I create a mock with an auth guard plugin", () => {
135
- mock = schmock({});
136
- mock("GET /protected", () => ({ secret: "data" }), {
137
- contentType: "application/json",
138
- }).pipe({
139
- name: "auth-plugin",
140
- process: (ctx, response) => {
141
- if (!ctx.headers.authorization) {
142
- return {
143
- context: ctx,
144
- response: [401, { error: "Unauthorized", code: "AUTH_REQUIRED" }],
145
- };
146
- }
147
- return { context: ctx, response };
148
- },
149
- });
150
- });
151
-
152
- When(
153
- "I request {string} without authorization",
154
- async (_, request: string) => {
155
- const [method, path] = request.split(" ");
156
- requestResponses = [await mock.handle(method as any, path)];
157
- },
158
- );
159
-
160
- Then("the status should be {int}", (_, status: number) => {
161
- expect(requestResponses[0].status).toBe(status);
162
- });
163
-
164
- And("I should receive:", (_, docString: string) => {
165
- const expected = JSON.parse(docString);
166
- expect(requestResponses[0].body).toEqual(expected);
167
- });
168
- });
169
-
170
- Scenario(
171
- "Pipeline order and response transformation",
172
- ({ Given, When, Then }) => {
173
- Given("I create a mock with three ordered step plugins", () => {
174
- mock = schmock({});
175
- mock("GET /data", () => ({ value: 42 }), {
176
- contentType: "application/json",
177
- })
178
- .pipe({
179
- name: "step-1",
180
- process: (ctx, response) => {
181
- ctx.state.set("step1", "processed");
182
- if (response) {
183
- return {
184
- context: ctx,
185
- response: { ...response, step1: "processed" },
186
- };
187
- }
188
- return { context: ctx, response };
189
- },
190
- })
191
- .pipe({
192
- name: "step-2",
193
- process: (ctx, response) => {
194
- if (response) {
195
- return {
196
- context: ctx,
197
- response: { ...response, step2: "processed" },
198
- };
199
- }
200
- return { context: ctx, response };
201
- },
202
- })
203
- .pipe({
204
- name: "step-3",
205
- process: (ctx, response) => {
206
- if (response) {
207
- return {
208
- context: ctx,
209
- response: { ...response, step3: "processed" },
210
- };
211
- }
212
- return { context: ctx, response };
213
- },
214
- });
215
- });
216
-
217
- When("I request {string}", async (_, request: string) => {
218
- const [method, path] = request.split(" ");
219
- requestResponses = [await mock.handle(method as any, path)];
220
- });
221
-
222
- Then("I should receive:", (_, docString: string) => {
223
- const expected = JSON.parse(docString);
224
- expect(requestResponses[0].body).toEqual(expected);
225
- });
226
- },
227
- );
228
-
229
- Scenario("Schema plugin in pipeline", ({ Given, When, Then, And }) => {
230
- Given("I create a mock with a metadata wrapper plugin", () => {
231
- mock = schmock({});
232
- mock(
233
- "GET /users",
234
- () => [
235
- { id: 1, name: "John Doe", email: "john@example.com" },
236
- { id: 2, name: "Jane Smith", email: "jane@example.com" },
237
- ],
238
- { contentType: "application/json" },
239
- ).pipe({
240
- name: "add-metadata",
241
- process: (ctx, response) => {
242
- if (response && Array.isArray(response)) {
243
- return {
244
- context: ctx,
245
- response: {
246
- users: response,
247
- count: response.length,
248
- generated_at: new Date().toISOString(),
249
- },
250
- };
251
- }
252
- return { context: ctx, response };
253
- },
254
- });
255
- });
256
-
257
- When("I request {string}", async (_, request: string) => {
258
- const [method, path] = request.split(" ");
259
- requestResponses = [await mock.handle(method as any, path)];
260
- });
261
-
262
- Then("the response should have a {string} array with {int} items", (_, property: string, count: number) => {
263
- expect(requestResponses[0].body).toHaveProperty(property);
264
- expect(Array.isArray(requestResponses[0].body[property])).toBe(true);
265
- expect(requestResponses[0].body[property]).toHaveLength(count);
266
- });
267
-
268
- And("the response should have {string} equal to {int}", (_, property: string, value: number) => {
269
- expect(requestResponses[0].body[property]).toBe(value);
270
- });
271
-
272
- And(
273
- "the response should have a {string} timestamp",
274
- (_, property: string) => {
275
- expect(requestResponses[0].body).toHaveProperty(property);
276
- expect(typeof requestResponses[0].body[property]).toBe("string");
277
- },
278
- );
279
- });
280
- });
@@ -1,276 +0,0 @@
1
- import { describeFeature, loadFeature } from "@amiceli/vitest-cucumber";
2
- import { expect } from "vitest";
3
- import type { CallableMockInstance } from "../types";
4
- import { schmock } from "../index";
5
-
6
- const feature = await loadFeature("../../features/request-history.feature");
7
-
8
- describeFeature(feature, ({ Scenario }) => {
9
- let mock: CallableMockInstance;
10
- let response: any;
11
-
12
- Scenario("Record multiple requests", ({ Given, When, And, Then }) => {
13
- Given("I create a mock with GET and POST user routes", () => {
14
- mock = schmock();
15
- mock("GET /users", [{ id: 1 }]);
16
- mock("POST /users", ({ body }) => [201, body]);
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
- And(
25
- "I request {string} with body:",
26
- async (_, request: string, docString: string) => {
27
- const [method, path] = request.split(" ");
28
- const body = JSON.parse(docString);
29
- response = await mock.handle(method as any, path, { body });
30
- },
31
- );
32
-
33
- And("I request {string}", async (_, request: string) => {
34
- const [method, path] = request.split(" ");
35
- response = await mock.handle(method as any, path);
36
- });
37
-
38
- Then("the call count should be 3", () => {
39
- expect(mock.callCount()).toBe(3);
40
- });
41
-
42
- And(
43
- "the call count for {string} should be {int}",
44
- (_, route: string, count: number) => {
45
- const [method, path] = route.split(" ");
46
- expect(mock.callCount(method as any, path)).toBe(count);
47
- },
48
- );
49
-
50
- And(
51
- "the call count for {string} should be {int} request",
52
- (_, route: string, count: number) => {
53
- const [method, path] = route.split(" ");
54
- expect(mock.callCount(method as any, path)).toBe(count);
55
- },
56
- );
57
- });
58
-
59
- Scenario("Filter history by method and path", ({ Given, When, And, Then }) => {
60
- Given("I create a mock with users and posts routes", () => {
61
- mock = schmock();
62
- mock("GET /users", []);
63
- mock("POST /users", ({ body }) => [201, body]);
64
- mock("GET /posts", []);
65
- });
66
-
67
- When("I request {string}", async (_, request: string) => {
68
- const [method, path] = request.split(" ");
69
- response = await mock.handle(method as any, path);
70
- });
71
-
72
- And(
73
- "I request {string} with body:",
74
- async (_, request: string, docString: string) => {
75
- const [method, path] = request.split(" ");
76
- const body = JSON.parse(docString);
77
- response = await mock.handle(method as any, path, { body });
78
- },
79
- );
80
-
81
- And("I request {string}", async (_, request: string) => {
82
- const [method, path] = request.split(" ");
83
- response = await mock.handle(method as any, path);
84
- });
85
-
86
- Then(
87
- "the history for {string} should have {int} record",
88
- (_, route: string, count: number) => {
89
- const [method, path] = route.split(" ");
90
- expect(mock.history(method as any, path)).toHaveLength(count);
91
- },
92
- );
93
-
94
- And(
95
- "the history for {string} should have {int} record",
96
- (_, route: string, count: number) => {
97
- const [method, path] = route.split(" ");
98
- expect(mock.history(method as any, path)).toHaveLength(count);
99
- },
100
- );
101
-
102
- And(
103
- "the history for {string} should have {int} entry",
104
- (_, route: string, count: number) => {
105
- const [method, path] = route.split(" ");
106
- expect(mock.history(method as any, path)).toHaveLength(count);
107
- },
108
- );
109
-
110
- And(
111
- "the history for {string} should have {int} entries",
112
- (_, route: string, count: number) => {
113
- const [method, path] = route.split(" ");
114
- expect(mock.history(method as any, path)).toHaveLength(count);
115
- },
116
- );
117
- });
118
-
119
- Scenario("Check if specific route was called", ({ Given, When, Then, And }) => {
120
- Given("I create a mock with users and posts list routes", () => {
121
- mock = schmock();
122
- mock("GET /users", []);
123
- mock("GET /posts", []);
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("{string} should have been called", (_, route: string) => {
132
- const [method, path] = route.split(" ");
133
- expect(mock.called(method as any, path)).toBe(true);
134
- });
135
-
136
- And("{string} should not have been called", (_, route: string) => {
137
- const [method, path] = route.split(" ");
138
- expect(mock.called(method as any, path)).toBe(false);
139
- });
140
- });
141
-
142
- Scenario("Request record captures full details", ({ Given, When, Then, And }) => {
143
- Given("I create a mock with a parameterized POST route", () => {
144
- mock = schmock();
145
- mock("POST /users/:id", ({ params, body }) => [
146
- 200,
147
- { ...(body as Record<string, unknown>), id: params.id },
148
- ]);
149
- });
150
-
151
- When(
152
- "I request {string} with headers and body:",
153
- async (_, request: string, docString: string) => {
154
- const [method, path] = request.split(" ");
155
- const options = JSON.parse(docString);
156
- response = await mock.handle(method as any, path, options);
157
- },
158
- );
159
-
160
- Then("the last request should have:", (_, table: any) => {
161
- const record = mock.lastRequest();
162
- expect(record).toBeDefined();
163
- for (const row of table) {
164
- const field = row.field as keyof typeof record;
165
- expect(record![field]).toBe(row.value);
166
- }
167
- });
168
-
169
- And(
170
- "the last request params should include {string} = {string}",
171
- (_, key: string, value: string) => {
172
- expect(mock.lastRequest()?.params[key]).toBe(value);
173
- },
174
- );
175
-
176
- And(
177
- "the last request headers should include {string} = {string}",
178
- (_, key: string, value: string) => {
179
- expect(mock.lastRequest()?.headers[key]).toBe(value);
180
- },
181
- );
182
-
183
- And(
184
- "the last request body should have property {string} with value {string}",
185
- (_, prop: string, value: string) => {
186
- expect((mock.lastRequest()?.body as any)?.[prop]).toBe(value);
187
- },
188
- );
189
-
190
- And("the last request should have a timestamp", () => {
191
- const record = mock.lastRequest();
192
- expect(record?.timestamp).toBeDefined();
193
- expect(typeof record?.timestamp).toBe("number");
194
- expect(record!.timestamp).toBeGreaterThan(0);
195
- });
196
-
197
- And(
198
- "the last request response status should be {int}",
199
- (_, status: number) => {
200
- expect(mock.lastRequest()?.response.status).toBe(status);
201
- },
202
- );
203
- });
204
-
205
- Scenario("Get last request for a specific route", ({ Given, When, And, Then }) => {
206
- Given("I create a mock echoing POST body at {string}", (_, path: string) => {
207
- mock = schmock();
208
- mock(`POST ${path}`, ({ body }) => [201, body]);
209
- });
210
-
211
- When(
212
- "I request {string} with body:",
213
- async (_, request: string, docString: string) => {
214
- const [method, path] = request.split(" ");
215
- const body = JSON.parse(docString);
216
- response = await mock.handle(method as any, path, { body });
217
- },
218
- );
219
-
220
- And(
221
- "I request {string} with body:",
222
- async (_, request: string, docString: string) => {
223
- const [method, path] = request.split(" ");
224
- const body = JSON.parse(docString);
225
- response = await mock.handle(method as any, path, { body });
226
- },
227
- );
228
-
229
- Then(
230
- "the last request for {string} body should have property {string} with value {string}",
231
- (_, route: string, prop: string, value: string) => {
232
- const [method, path] = route.split(" ");
233
- const record = mock.lastRequest(method as any, path);
234
- expect((record?.body as any)?.[prop]).toBe(value);
235
- },
236
- );
237
- });
238
-
239
- Scenario("404 requests are not recorded in history", ({ Given, When, Then, And }) => {
240
- Given("I create a mock with only a users route", () => {
241
- mock = schmock();
242
- mock("GET /users", []);
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("the mock should not have been called", () => {
251
- expect(mock.called()).toBe(false);
252
- });
253
-
254
- And("the call count should be 0", () => {
255
- expect(mock.callCount()).toBe(0);
256
- });
257
- });
258
-
259
- Scenario("maxHistorySize bounds the history with FIFO eviction", ({ Given, When, Then }) => {
260
- Given("I create a mock with maxHistorySize {int} and a users route", (_, maxHistorySize: number) => {
261
- mock = schmock({ maxHistorySize });
262
- mock("GET /users", []);
263
- });
264
-
265
- When("I issue {int} requests to {string}", async (_, count: number, request: string) => {
266
- const [method, path] = request.split(" ");
267
- for (let i = 0; i < count; i++) {
268
- await mock.handle(method as any, path);
269
- }
270
- });
271
-
272
- Then("the call count should be {int}", (_, expected: number) => {
273
- expect(mock.callCount()).toBe(expected);
274
- });
275
- });
276
- });
@@ -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
- });