@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.
- 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/builder.d.ts +31 -10
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +760 -190
- 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 +39 -4
- package/dist/http-helpers.d.ts.map +1 -1
- package/dist/http-helpers.js +147 -49
- package/dist/index.d.ts +292 -34
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/interceptor.d.ts +11 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +316 -169
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +12 -3
- package/dist/plugin-pipeline.d.ts +3 -3
- package/dist/plugin-pipeline.d.ts.map +1 -1
- package/dist/plugin-pipeline.js +29 -14
- 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 +39 -2
- 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 +14 -6
- package/src/audit-core-builder.test.ts +0 -218
- package/src/audit-response-guard.test.ts +0 -38
- package/src/binary.test.ts +0 -126
- package/src/binary.ts +0 -11
- package/src/builder.test.ts +0 -289
- package/src/builder.ts +0 -748
- 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.test.ts +0 -39
- package/src/http-helpers.ts +0 -149
- package/src/index.ts +0 -152
- package/src/interceptor.test.ts +0 -488
- package/src/interceptor.ts +0 -407
- package/src/namespace.test.ts +0 -274
- package/src/parser.property.test.ts +0 -630
- package/src/parser.test.ts +0 -148
- package/src/parser.ts +0 -64
- package/src/plugin-pipeline.ts +0 -208
- package/src/plugin-system.test.ts +0 -697
- package/src/response-parser.ts +0 -114
- 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 -234
- package/src/smart-defaults.test.ts +0 -361
- package/src/steps/async-support.steps.ts +0 -421
- package/src/steps/audit-core-builder.steps.ts +0 -188
- package/src/steps/audit-onerror-tuple.steps.ts +0 -83
- 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 -555
- package/src/steps/fetch-interceptor.steps.ts +0 -457
- package/src/steps/fluent-api.steps.ts +0 -255
- package/src/steps/http-methods.steps.ts +0 -342
- package/src/steps/lifecycle-events.steps.ts +0 -149
- package/src/steps/performance-reliability.steps.ts +0 -90
- package/src/steps/plugin-integration.steps.ts +0 -334
- package/src/steps/request-history.steps.ts +0 -458
- 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 -227
- package/src/steps/state-concurrency.steps.ts +0 -167
- package/src/types.ts +0 -36
package/src/builder.test.ts
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { schmock } from "./index";
|
|
3
|
-
|
|
4
|
-
describe("schmock callable API", () => {
|
|
5
|
-
describe("callable instance", () => {
|
|
6
|
-
it("returns callable mock instance from factory", () => {
|
|
7
|
-
const mock = schmock();
|
|
8
|
-
expect(mock).toBeDefined();
|
|
9
|
-
expect(typeof mock).toBe("function");
|
|
10
|
-
expect(mock.handle).toBeTypeOf("function");
|
|
11
|
-
expect(mock.pipe).toBeTypeOf("function");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("allows defining routes through function calls", () => {
|
|
15
|
-
const mock = schmock();
|
|
16
|
-
const result = mock("GET /users", () => [], {});
|
|
17
|
-
|
|
18
|
-
expect(result).toBe(mock); // Should return same instance for chaining
|
|
19
|
-
expect(result.pipe).toBeTypeOf("function");
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("supports chaining with pipe method", () => {
|
|
23
|
-
const mock = schmock();
|
|
24
|
-
const result = mock("GET /users", () => [], {}).pipe({
|
|
25
|
-
name: "test-plugin",
|
|
26
|
-
process: (ctx, response) => ({ context: ctx, response }),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
expect(result).toBe(mock); // Should return same instance for chaining
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe("request handling", () => {
|
|
34
|
-
it("handles simple GET request", async () => {
|
|
35
|
-
const mock = schmock();
|
|
36
|
-
mock("GET /users", () => [{ id: 1, name: "John" }], {});
|
|
37
|
-
|
|
38
|
-
const response = await mock.handle("GET", "/users");
|
|
39
|
-
|
|
40
|
-
expect(response.status).toBe(200);
|
|
41
|
-
expect(response.body).toEqual([{ id: 1, name: "John" }]);
|
|
42
|
-
expect(response.headers).toEqual({ "content-type": "application/json" });
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("returns 404 for undefined routes", async () => {
|
|
46
|
-
const mock = schmock();
|
|
47
|
-
mock("GET /users", () => [], {});
|
|
48
|
-
|
|
49
|
-
const response = await mock.handle("GET", "/posts");
|
|
50
|
-
|
|
51
|
-
expect(response.status).toBe(404);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("handles route with parameters", async () => {
|
|
55
|
-
const mock = schmock();
|
|
56
|
-
mock("GET /users/:id", ({ params }) => ({ userId: params.id }), {});
|
|
57
|
-
|
|
58
|
-
const response = await mock.handle("GET", "/users/123");
|
|
59
|
-
|
|
60
|
-
expect(response.status).toBe(200);
|
|
61
|
-
expect(response.body).toEqual({ userId: "123" });
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("handles custom status codes via tuple", async () => {
|
|
65
|
-
const mock = schmock();
|
|
66
|
-
mock("POST /users", ({ body }) => [201, { id: 1, ...body }], {});
|
|
67
|
-
|
|
68
|
-
const response = await mock.handle("POST", "/users", {
|
|
69
|
-
body: { name: "Alice" },
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
expect(response.status).toBe(201);
|
|
73
|
-
expect(response.body).toEqual({ id: 1, name: "Alice" });
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("handles custom headers via triple tuple", async () => {
|
|
77
|
-
const mock = schmock();
|
|
78
|
-
mock(
|
|
79
|
-
"POST /users",
|
|
80
|
-
({ body }) => [201, { id: 1, ...body }, { Location: "/users/1" }],
|
|
81
|
-
{},
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
const response = await mock.handle("POST", "/users", {
|
|
85
|
-
body: { name: "Alice" },
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(response.status).toBe(201);
|
|
89
|
-
expect(response.headers).toEqual({
|
|
90
|
-
Location: "/users/1",
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe("state management", () => {
|
|
96
|
-
it("maintains state across requests with global config", async () => {
|
|
97
|
-
const globalState = { count: 0 };
|
|
98
|
-
const mock = schmock({ state: globalState });
|
|
99
|
-
mock(
|
|
100
|
-
"GET /increment",
|
|
101
|
-
({ state }) => {
|
|
102
|
-
state.count++;
|
|
103
|
-
return { value: state.count };
|
|
104
|
-
},
|
|
105
|
-
{},
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
const first = await mock.handle("GET", "/increment");
|
|
109
|
-
const second = await mock.handle("GET", "/increment");
|
|
110
|
-
|
|
111
|
-
expect(first.body).toEqual({ value: 1 });
|
|
112
|
-
expect(second.body).toEqual({ value: 2 });
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("shares state between routes with global config", async () => {
|
|
116
|
-
const globalState = { users: [] as unknown[] };
|
|
117
|
-
const mock = schmock({ state: globalState });
|
|
118
|
-
|
|
119
|
-
mock(
|
|
120
|
-
"POST /users",
|
|
121
|
-
({ body, state }) => {
|
|
122
|
-
const user = { id: Date.now(), ...body };
|
|
123
|
-
state.users.push(user);
|
|
124
|
-
return [201, user];
|
|
125
|
-
},
|
|
126
|
-
{},
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
mock("GET /users", ({ state }) => state.users, {});
|
|
130
|
-
|
|
131
|
-
await mock.handle("POST", "/users", { body: { name: "John" } });
|
|
132
|
-
const response = await mock.handle("GET", "/users");
|
|
133
|
-
|
|
134
|
-
expect(response.body).toHaveLength(1);
|
|
135
|
-
expect(response.body[0]).toHaveProperty("name", "John");
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
describe("configuration", () => {
|
|
140
|
-
it("applies namespace to all routes", async () => {
|
|
141
|
-
const mock = schmock({ namespace: "/api/v1" });
|
|
142
|
-
mock("GET /users", () => [], {});
|
|
143
|
-
|
|
144
|
-
const response = await mock.handle("GET", "/api/v1/users");
|
|
145
|
-
|
|
146
|
-
expect(response.status).toBe(200);
|
|
147
|
-
expect(response.body).toEqual([]);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("returns 404 without namespace prefix", async () => {
|
|
151
|
-
const mock = schmock({ namespace: "/api/v1" });
|
|
152
|
-
mock("GET /users", () => [], {});
|
|
153
|
-
|
|
154
|
-
const response = await mock.handle("GET", "/users");
|
|
155
|
-
|
|
156
|
-
expect(response.status).toBe(404);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe("request context", () => {
|
|
161
|
-
it("provides query parameters", async () => {
|
|
162
|
-
const mock = schmock();
|
|
163
|
-
mock(
|
|
164
|
-
"GET /search",
|
|
165
|
-
({ query }) => ({
|
|
166
|
-
results: [],
|
|
167
|
-
query: query.q,
|
|
168
|
-
}),
|
|
169
|
-
{},
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
const response = await mock.handle("GET", "/search", {
|
|
173
|
-
query: { q: "test" },
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
expect(response.body).toEqual({
|
|
177
|
-
results: [],
|
|
178
|
-
query: "test",
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("provides headers", async () => {
|
|
183
|
-
const mock = schmock();
|
|
184
|
-
mock(
|
|
185
|
-
"GET /auth",
|
|
186
|
-
({ headers }) => ({
|
|
187
|
-
authenticated: headers.authorization === "Bearer token123",
|
|
188
|
-
}),
|
|
189
|
-
{},
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
const response = await mock.handle("GET", "/auth", {
|
|
193
|
-
headers: { authorization: "Bearer token123" },
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(response.body).toEqual({ authenticated: true });
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it("provides method and path in context", async () => {
|
|
200
|
-
const mock = schmock();
|
|
201
|
-
mock("GET /info", ({ method, path }) => ({ method, path }), {});
|
|
202
|
-
|
|
203
|
-
const response = await mock.handle("GET", "/info");
|
|
204
|
-
|
|
205
|
-
expect(response.body).toEqual({
|
|
206
|
-
method: "GET",
|
|
207
|
-
path: "/info",
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
describe("contentType auto-detection", () => {
|
|
213
|
-
it("defaults to application/json for function generators", async () => {
|
|
214
|
-
const mock = schmock();
|
|
215
|
-
mock("GET /users", () => [{ id: 1 }], {});
|
|
216
|
-
|
|
217
|
-
const response = await mock.handle("GET", "/users");
|
|
218
|
-
expect(response.status).toBe(200);
|
|
219
|
-
expect(response.body).toEqual([{ id: 1 }]);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it("defaults to text/plain for string generators", async () => {
|
|
223
|
-
const mock = schmock();
|
|
224
|
-
mock("GET /text", "Hello World", {});
|
|
225
|
-
|
|
226
|
-
const response = await mock.handle("GET", "/text");
|
|
227
|
-
expect(response.status).toBe(200);
|
|
228
|
-
expect(response.body).toBe("Hello World");
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("defaults to application/json for object generators", async () => {
|
|
232
|
-
const mock = schmock();
|
|
233
|
-
mock("GET /users", [{ id: 1, name: "John" }], {});
|
|
234
|
-
|
|
235
|
-
const response = await mock.handle("GET", "/users");
|
|
236
|
-
expect(response.status).toBe(200);
|
|
237
|
-
expect(response.body).toEqual([{ id: 1, name: "John" }]);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it("allows explicit contentType override", async () => {
|
|
241
|
-
const mock = schmock();
|
|
242
|
-
mock("GET /json", "Hello World", { contentType: "application/json" });
|
|
243
|
-
|
|
244
|
-
const response = await mock.handle("GET", "/json");
|
|
245
|
-
expect(response.status).toBe(200);
|
|
246
|
-
expect(response.body).toBe("Hello World");
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it("validates JSON data for application/json contentType", () => {
|
|
250
|
-
const mock = schmock();
|
|
251
|
-
|
|
252
|
-
// This should work - valid JSON data
|
|
253
|
-
expect(() => {
|
|
254
|
-
mock("GET /users", [{ id: 1 }], { contentType: "application/json" });
|
|
255
|
-
}).not.toThrow();
|
|
256
|
-
|
|
257
|
-
// This should fail - circular reference can't be JSON serialized
|
|
258
|
-
const circular: any = {};
|
|
259
|
-
circular.self = circular;
|
|
260
|
-
|
|
261
|
-
expect(() => {
|
|
262
|
-
mock("GET /users", circular, { contentType: "application/json" });
|
|
263
|
-
}).toThrow(
|
|
264
|
-
"Generator data is not valid JSON but contentType is application/json",
|
|
265
|
-
);
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
describe("plugin integration", () => {
|
|
270
|
-
it("supports plugin pipeline with pipe method", async () => {
|
|
271
|
-
const mock = schmock();
|
|
272
|
-
mock("GET /users", [{ id: 1, name: "John" }], {}).pipe({
|
|
273
|
-
name: "test-plugin",
|
|
274
|
-
process: (ctx, pluginResponse) => ({
|
|
275
|
-
context: ctx,
|
|
276
|
-
response: { data: pluginResponse, processed: true },
|
|
277
|
-
}),
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
const response = await mock.handle("GET", "/users");
|
|
281
|
-
|
|
282
|
-
expect(response.status).toBe(200);
|
|
283
|
-
expect(response.body).toEqual({
|
|
284
|
-
data: [{ id: 1, name: "John" }],
|
|
285
|
-
processed: true,
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
});
|