@schmock/core 2.3.0 → 2.4.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 (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 +18 -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,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
- });