@schmock/core 2.2.3 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/abort.d.ts +3 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +30 -0
- package/dist/binary.d.ts +8 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +9 -0
- package/dist/builder.d.ts +31 -10
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +804 -203
- package/dist/constants.d.ts +38 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +123 -2
- package/dist/errors.d.ts +14 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +41 -6
- package/dist/helpers.d.ts +9 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +18 -2
- package/dist/http-helpers.d.ts +52 -5
- package/dist/http-helpers.d.ts.map +1 -1
- package/dist/http-helpers.js +153 -37
- package/dist/index.d.ts +381 -60
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/interceptor.d.ts +11 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +354 -156
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +12 -3
- package/dist/plugin-pipeline.d.ts +11 -4
- package/dist/plugin-pipeline.d.ts.map +1 -1
- package/dist/plugin-pipeline.js +117 -39
- package/dist/response-normalizer.d.ts +16 -0
- package/dist/response-normalizer.d.ts.map +1 -0
- package/dist/response-normalizer.js +316 -0
- package/dist/response-parser.d.ts.map +1 -1
- package/dist/response-parser.js +85 -18
- package/dist/route-matcher.d.ts +3 -0
- package/dist/route-matcher.d.ts.map +1 -1
- package/dist/route-matcher.js +12 -6
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +18 -8
- package/src/audit-core-builder.test.ts +0 -218
- package/src/audit-response-guard.test.ts +0 -38
- package/src/builder.test.ts +0 -289
- package/src/builder.ts +0 -701
- package/src/constants.test.ts +0 -99
- package/src/constants.ts +0 -73
- package/src/debug.test.ts +0 -241
- package/src/delay.test.ts +0 -319
- package/src/dist-shape.test.ts +0 -35
- package/src/errors.test.ts +0 -223
- package/src/errors.ts +0 -130
- package/src/factory.test.ts +0 -133
- package/src/helpers.test.ts +0 -147
- package/src/helpers.ts +0 -58
- package/src/http-helpers.ts +0 -113
- package/src/index.ts +0 -151
- package/src/interceptor.test.ts +0 -291
- package/src/interceptor.ts +0 -320
- package/src/namespace.test.ts +0 -274
- package/src/parser.property.test.ts +0 -594
- package/src/parser.test.ts +0 -148
- package/src/parser.ts +0 -64
- package/src/plugin-pipeline.ts +0 -103
- package/src/plugin-system.test.ts +0 -602
- package/src/response-parser.ts +0 -75
- package/src/response-parsing.test.ts +0 -333
- package/src/route-matcher.ts +0 -69
- package/src/route-matching.test.ts +0 -394
- package/src/server.test.ts +0 -165
- package/src/smart-defaults.test.ts +0 -361
- package/src/steps/async-support.steps.ts +0 -400
- package/src/steps/audit-core-builder.steps.ts +0 -188
- package/src/steps/audit-onerror-tuple.steps.ts +0 -99
- package/src/steps/basic-usage.steps.ts +0 -245
- package/src/steps/developer-experience.steps.ts +0 -204
- package/src/steps/error-handling.steps.ts +0 -345
- package/src/steps/fluent-api.steps.ts +0 -255
- package/src/steps/http-methods.steps.ts +0 -331
- package/src/steps/interceptor.steps.ts +0 -260
- package/src/steps/lifecycle-events.steps.ts +0 -142
- package/src/steps/performance-reliability.steps.ts +0 -423
- package/src/steps/plugin-integration.steps.ts +0 -280
- package/src/steps/request-history.steps.ts +0 -276
- package/src/steps/response-delay.steps.ts +0 -88
- package/src/steps/route-key-format.steps.ts +0 -99
- package/src/steps/standalone-server.steps.ts +0 -233
- package/src/steps/state-concurrency.steps.ts +0 -739
- package/src/steps/stateful-workflows.steps.ts +0 -353
- package/src/types.ts +0 -36
|
@@ -1,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
|
-
});
|
|
@@ -1,233 +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/standalone-server.feature");
|
|
6
|
-
|
|
7
|
-
describeFeature(feature, ({ Scenario }) => {
|
|
8
|
-
let mock: Schmock.CallableMockInstance;
|
|
9
|
-
let serverInfo: Schmock.ServerInfo;
|
|
10
|
-
let httpResponse: Response;
|
|
11
|
-
|
|
12
|
-
function baseUrl(): string {
|
|
13
|
-
return `http://${serverInfo.hostname}:${serverInfo.port}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
Scenario("Start and stop a simple server", ({ Given, When, Then, And }) => {
|
|
17
|
-
Given("I create a mock with a GET /hello route", () => {
|
|
18
|
-
mock = schmock();
|
|
19
|
-
mock("GET /hello", { message: "hello" });
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
When("I start the server on a random port", async () => {
|
|
23
|
-
serverInfo = await mock.listen(0);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
Then("the server should be running", () => {
|
|
27
|
-
expect(serverInfo.port).toBeGreaterThan(0);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
When("I fetch {string} from the server", async (_, route: string) => {
|
|
31
|
-
const [, path] = route.split(" ");
|
|
32
|
-
httpResponse = await fetch(`${baseUrl()}${path}`);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
Then("the HTTP response status should be {int}", (_, status: number) => {
|
|
36
|
-
expect(httpResponse.status).toBe(status);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
And(
|
|
40
|
-
"the HTTP response body should have {string} equal to {string}",
|
|
41
|
-
async (_, key: string, value: string) => {
|
|
42
|
-
const body = await httpResponse.json();
|
|
43
|
-
expect(body[key]).toBe(value);
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
When("I stop the server", () => {
|
|
48
|
-
mock.close();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
Then("the server should not be running", async () => {
|
|
52
|
-
try {
|
|
53
|
-
await fetch(`${baseUrl()}/hello`);
|
|
54
|
-
expect.unreachable("Should not be able to connect");
|
|
55
|
-
} catch {
|
|
56
|
-
// Connection refused — server is down
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
Scenario("Handle POST with JSON body", ({ Given, When, Then, And }) => {
|
|
62
|
-
Given("I create a mock echoing POST at {string}", (_, path: string) => {
|
|
63
|
-
mock = schmock();
|
|
64
|
-
mock(`POST ${path}`, ({ body }) => body);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
When("I start the server on a random port", async () => {
|
|
68
|
-
serverInfo = await mock.listen(0);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
And(
|
|
72
|
-
"I fetch {string} with JSON body:",
|
|
73
|
-
async (_, route: string, docString: string) => {
|
|
74
|
-
const [method, path] = route.split(" ");
|
|
75
|
-
httpResponse = await fetch(`${baseUrl()}${path}`, {
|
|
76
|
-
method,
|
|
77
|
-
headers: { "content-type": "application/json" },
|
|
78
|
-
body: docString,
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
Then(
|
|
84
|
-
"the response status from POST should be {int}",
|
|
85
|
-
(_, status: number) => {
|
|
86
|
-
expect(httpResponse.status).toBe(status);
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
And(
|
|
91
|
-
"the response body from POST should have {string} equal to {string}",
|
|
92
|
-
async (_, key: string, value: string) => {
|
|
93
|
-
const body = await httpResponse.json();
|
|
94
|
-
expect(body[key]).toBe(value);
|
|
95
|
-
},
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
When("I stop the server", () => {
|
|
99
|
-
mock.close();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
Scenario(
|
|
104
|
-
"Return 404 for unregistered routes",
|
|
105
|
-
({ Given, When, And, Then }) => {
|
|
106
|
-
Given("I create a mock with a GET /hello route", () => {
|
|
107
|
-
mock = schmock();
|
|
108
|
-
mock("GET /hello", { message: "hello" });
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
When("I start the server on a random port", async () => {
|
|
112
|
-
serverInfo = await mock.listen(0);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
And("I fetch {string} from the server", async (_, route: string) => {
|
|
116
|
-
const [, path] = route.split(" ");
|
|
117
|
-
httpResponse = await fetch(`${baseUrl()}${path}`);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
Then("the HTTP response status should be {int}", (_, status: number) => {
|
|
121
|
-
expect(httpResponse.status).toBe(status);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
When("I stop the server", () => {
|
|
125
|
-
mock.close();
|
|
126
|
-
});
|
|
127
|
-
},
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
Scenario("Query parameters are forwarded", ({ Given, When, And, Then }) => {
|
|
131
|
-
let parsedBody: Record<string, string>;
|
|
132
|
-
|
|
133
|
-
Given(
|
|
134
|
-
"I create a mock reflecting query params at {string}",
|
|
135
|
-
(_, route: string) => {
|
|
136
|
-
const [method, path] = route.split(" ");
|
|
137
|
-
mock = schmock();
|
|
138
|
-
mock(`${method} ${path}` as Schmock.RouteKey, ({ query }) => query);
|
|
139
|
-
},
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
When("I start the server on a random port", async () => {
|
|
143
|
-
serverInfo = await mock.listen(0);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
And("I fetch {string} from the server", async (_, route: string) => {
|
|
147
|
-
const [, pathWithQuery] = route.split(" ");
|
|
148
|
-
httpResponse = await fetch(`${baseUrl()}${pathWithQuery}`);
|
|
149
|
-
parsedBody = await httpResponse.json();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
Then("the HTTP response status should be {int}", (_, status: number) => {
|
|
153
|
-
expect(httpResponse.status).toBe(status);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
And(
|
|
157
|
-
"the HTTP response body should have {string} equal to {string}",
|
|
158
|
-
(_, key: string, value: string) => {
|
|
159
|
-
expect(parsedBody[key]).toBe(value);
|
|
160
|
-
},
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
And(
|
|
164
|
-
"the query param {string} should equal {string}",
|
|
165
|
-
(_, key: string, value: string) => {
|
|
166
|
-
expect(parsedBody[key]).toBe(value);
|
|
167
|
-
},
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
When("I stop the server", () => {
|
|
171
|
-
mock.close();
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
Scenario("Double listen throws an error", ({ Given, When, Then }) => {
|
|
176
|
-
Given("I create a mock with a GET /hello route", () => {
|
|
177
|
-
mock = schmock();
|
|
178
|
-
mock("GET /hello", { message: "hello" });
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
When("I start the server on a random port", async () => {
|
|
182
|
-
serverInfo = await mock.listen(0);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
Then("starting the server again should throw", () => {
|
|
186
|
-
expect(() => mock.listen(0)).toThrow("Server is already running");
|
|
187
|
-
mock.close();
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
Scenario("Close is idempotent", ({ Given, When, And, Then }) => {
|
|
192
|
-
Given("I create a mock with a GET /hello route", () => {
|
|
193
|
-
mock = schmock();
|
|
194
|
-
mock("GET /hello", { message: "hello" });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
When("I start the server on a random port", async () => {
|
|
198
|
-
serverInfo = await mock.listen(0);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
And("I stop the server", () => {
|
|
202
|
-
mock.close();
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
Then("stopping the server again should not throw", () => {
|
|
206
|
-
expect(() => mock.close()).not.toThrow();
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
Scenario("Reset stops the server", ({ Given, When, And, Then }) => {
|
|
211
|
-
Given("I create a mock with a GET /hello route", () => {
|
|
212
|
-
mock = schmock();
|
|
213
|
-
mock("GET /hello", { message: "hello" });
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
When("I start the server on a random port", async () => {
|
|
217
|
-
serverInfo = await mock.listen(0);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
And("I reset the mock", () => {
|
|
221
|
-
mock.reset();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
Then("the server should not be running", async () => {
|
|
225
|
-
try {
|
|
226
|
-
await fetch(`${baseUrl()}/hello`);
|
|
227
|
-
expect.unreachable("Should not be able to connect");
|
|
228
|
-
} catch {
|
|
229
|
-
// Connection refused — server is down
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
});
|