msw-fetch-mock 0.3.0 → 0.3.2
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/README.md +72 -6
- package/dist/browser.cjs +43 -0
- package/dist/browser.d.cts +15 -0
- package/dist/browser.d.ts +15 -9
- package/dist/browser.js +42 -7
- package/dist/chunk-3RAWYKAG.js +551 -0
- package/dist/chunk-IOGQ34QL.js +27 -0
- package/dist/chunk-N6B7UP6B.cjs +551 -0
- package/dist/chunk-PJU5FUNI.cjs +58 -0
- package/dist/chunk-PUVZ7LB4.js +58 -0
- package/dist/chunk-QKIKWNFZ.cjs +27 -0
- package/dist/fetch-mock-DhiqmHdF.d.cts +199 -0
- package/dist/fetch-mock-DhiqmHdF.d.ts +199 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +19 -1
- package/dist/legacy.cjs +71 -0
- package/dist/legacy.d.cts +38 -0
- package/dist/legacy.d.ts +38 -0
- package/dist/legacy.js +71 -0
- package/dist/node.cjs +19 -0
- package/dist/node.d.cts +18 -0
- package/dist/node.d.ts +17 -10
- package/dist/node.js +19 -12
- package/docs/api.md +121 -13
- package/docs/msw-v1-legacy.md +94 -0
- package/package.json +34 -10
- package/dist/browser-adapter.d.ts +0 -10
- package/dist/browser-adapter.d.ts.map +0 -1
- package/dist/browser-adapter.js +0 -20
- package/dist/browser.d.ts.map +0 -1
- package/dist/fetch-mock.d.ts +0 -31
- package/dist/fetch-mock.d.ts.map +0 -1
- package/dist/fetch-mock.js +0 -347
- package/dist/index.d.ts.map +0 -1
- package/dist/mock-call-history.d.ts +0 -65
- package/dist/mock-call-history.d.ts.map +0 -1
- package/dist/mock-call-history.js +0 -140
- package/dist/node-adapter.d.ts +0 -11
- package/dist/node-adapter.d.ts.map +0 -1
- package/dist/node-adapter.js +0 -34
- package/dist/node.d.ts.map +0 -1
- package/dist/types.d.ts +0 -74
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
// src/mock-call-history.ts
|
|
2
|
+
var MockCallHistoryLog = class {
|
|
3
|
+
body;
|
|
4
|
+
method;
|
|
5
|
+
headers;
|
|
6
|
+
fullUrl;
|
|
7
|
+
origin;
|
|
8
|
+
path;
|
|
9
|
+
searchParams;
|
|
10
|
+
protocol;
|
|
11
|
+
host;
|
|
12
|
+
port;
|
|
13
|
+
hash;
|
|
14
|
+
constructor(data) {
|
|
15
|
+
this.body = data.body;
|
|
16
|
+
this.method = data.method;
|
|
17
|
+
this.headers = data.headers;
|
|
18
|
+
this.fullUrl = data.fullUrl;
|
|
19
|
+
this.origin = data.origin;
|
|
20
|
+
this.path = data.path;
|
|
21
|
+
this.searchParams = data.searchParams;
|
|
22
|
+
this.protocol = data.protocol;
|
|
23
|
+
this.host = data.host;
|
|
24
|
+
this.port = data.port;
|
|
25
|
+
this.hash = data.hash;
|
|
26
|
+
}
|
|
27
|
+
json() {
|
|
28
|
+
if (this.body === null) return null;
|
|
29
|
+
return JSON.parse(this.body);
|
|
30
|
+
}
|
|
31
|
+
toMap() {
|
|
32
|
+
return /* @__PURE__ */ new Map([
|
|
33
|
+
["body", this.body],
|
|
34
|
+
["method", this.method],
|
|
35
|
+
["headers", this.headers],
|
|
36
|
+
["fullUrl", this.fullUrl],
|
|
37
|
+
["origin", this.origin],
|
|
38
|
+
["path", this.path],
|
|
39
|
+
["searchParams", this.searchParams],
|
|
40
|
+
["protocol", this.protocol],
|
|
41
|
+
["host", this.host],
|
|
42
|
+
["port", this.port],
|
|
43
|
+
["hash", this.hash]
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
toString() {
|
|
47
|
+
return [
|
|
48
|
+
`method->${this.method}`,
|
|
49
|
+
`protocol->${this.protocol}`,
|
|
50
|
+
`host->${this.host}`,
|
|
51
|
+
`port->${this.port}`,
|
|
52
|
+
`origin->${this.origin}`,
|
|
53
|
+
`path->${this.path}`,
|
|
54
|
+
`hash->${this.hash}`,
|
|
55
|
+
`fullUrl->${this.fullUrl}`
|
|
56
|
+
].join("|");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var MockCallHistory = class {
|
|
60
|
+
logs = [];
|
|
61
|
+
get length() {
|
|
62
|
+
return this.logs.length;
|
|
63
|
+
}
|
|
64
|
+
record(data) {
|
|
65
|
+
this.logs.push(data instanceof MockCallHistoryLog ? data : new MockCallHistoryLog(data));
|
|
66
|
+
}
|
|
67
|
+
called(criteria) {
|
|
68
|
+
if (criteria === void 0) return this.logs.length > 0;
|
|
69
|
+
return this.filterCalls(criteria).length > 0;
|
|
70
|
+
}
|
|
71
|
+
calls() {
|
|
72
|
+
return [...this.logs];
|
|
73
|
+
}
|
|
74
|
+
firstCall(criteria) {
|
|
75
|
+
if (criteria === void 0) return this.logs[0];
|
|
76
|
+
return this.filterCalls(criteria)[0];
|
|
77
|
+
}
|
|
78
|
+
lastCall(criteria) {
|
|
79
|
+
if (criteria === void 0) return this.logs[this.logs.length - 1];
|
|
80
|
+
const filtered = this.filterCalls(criteria);
|
|
81
|
+
return filtered[filtered.length - 1];
|
|
82
|
+
}
|
|
83
|
+
nthCall(n, criteria) {
|
|
84
|
+
if (criteria === void 0) return this.logs[n - 1];
|
|
85
|
+
return this.filterCalls(criteria)[n - 1];
|
|
86
|
+
}
|
|
87
|
+
clear() {
|
|
88
|
+
this.logs = [];
|
|
89
|
+
}
|
|
90
|
+
[Symbol.iterator]() {
|
|
91
|
+
return this.logs[Symbol.iterator]();
|
|
92
|
+
}
|
|
93
|
+
filterCalls(criteria, options) {
|
|
94
|
+
if (typeof criteria === "function") {
|
|
95
|
+
return this.logs.filter(criteria);
|
|
96
|
+
}
|
|
97
|
+
if (criteria instanceof RegExp) {
|
|
98
|
+
return this.logs.filter((log) => criteria.test(log.toString()));
|
|
99
|
+
}
|
|
100
|
+
const operator = options?.operator ?? "OR";
|
|
101
|
+
const keys = Object.keys(criteria);
|
|
102
|
+
const predicates = keys.filter((key) => criteria[key] !== void 0).map((key) => (log) => log[key] === criteria[key]);
|
|
103
|
+
if (predicates.length === 0) return [...this.logs];
|
|
104
|
+
return this.logs.filter(
|
|
105
|
+
(log) => operator === "AND" ? predicates.every((p) => p(log)) : predicates.some((p) => p(log))
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
filterBy(field, filter) {
|
|
109
|
+
return this.logs.filter(
|
|
110
|
+
(log) => typeof filter === "string" ? log[field] === filter : filter.test(String(log[field]))
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
filterCallsByMethod(filter) {
|
|
114
|
+
return this.filterBy("method", filter);
|
|
115
|
+
}
|
|
116
|
+
filterCallsByPath(filter) {
|
|
117
|
+
return this.filterBy("path", filter);
|
|
118
|
+
}
|
|
119
|
+
filterCallsByOrigin(filter) {
|
|
120
|
+
return this.filterBy("origin", filter);
|
|
121
|
+
}
|
|
122
|
+
filterCallsByProtocol(filter) {
|
|
123
|
+
return this.filterBy("protocol", filter);
|
|
124
|
+
}
|
|
125
|
+
filterCallsByHost(filter) {
|
|
126
|
+
return this.filterBy("host", filter);
|
|
127
|
+
}
|
|
128
|
+
filterCallsByPort(filter) {
|
|
129
|
+
return this.filterBy("port", filter);
|
|
130
|
+
}
|
|
131
|
+
filterCallsByHash(filter) {
|
|
132
|
+
return this.filterBy("hash", filter);
|
|
133
|
+
}
|
|
134
|
+
filterCallsByFullUrl(filter) {
|
|
135
|
+
return this.filterBy("fullUrl", filter);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/matchers.ts
|
|
140
|
+
function isPending(p) {
|
|
141
|
+
if (p.persist) return p.timesInvoked === 0;
|
|
142
|
+
return p.timesInvoked < p.times;
|
|
143
|
+
}
|
|
144
|
+
function escapeRegExp(str) {
|
|
145
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
146
|
+
}
|
|
147
|
+
function matchesValue(value, matcher) {
|
|
148
|
+
if (typeof matcher === "string") return value === matcher;
|
|
149
|
+
if (matcher instanceof RegExp) return matcher.test(value);
|
|
150
|
+
return matcher(value);
|
|
151
|
+
}
|
|
152
|
+
function matchPath(request, origin, pathMatcher) {
|
|
153
|
+
if (typeof pathMatcher === "string") return true;
|
|
154
|
+
const url = new URL(request.url);
|
|
155
|
+
const originPrefix = new URL(origin).pathname.replace(/\/$/, "");
|
|
156
|
+
const fullPath = url.pathname + url.search;
|
|
157
|
+
const relativePath = fullPath.startsWith(originPrefix) ? fullPath.slice(originPrefix.length) : fullPath;
|
|
158
|
+
return matchesValue(relativePath, pathMatcher);
|
|
159
|
+
}
|
|
160
|
+
function matchQuery(request, query) {
|
|
161
|
+
if (!query) return true;
|
|
162
|
+
const url = new URL(request.url);
|
|
163
|
+
for (const [key, value] of Object.entries(query)) {
|
|
164
|
+
if (url.searchParams.get(key) !== value) return false;
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
function matchHeaders(request, headers) {
|
|
169
|
+
if (!headers) return true;
|
|
170
|
+
for (const [key, matcher] of Object.entries(headers)) {
|
|
171
|
+
const value = request.headers.get(key);
|
|
172
|
+
if (value === null || !matchesValue(value, matcher)) return false;
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
function matchBody(bodyText, bodyMatcher) {
|
|
177
|
+
if (!bodyMatcher) return true;
|
|
178
|
+
return matchesValue(bodyText ?? "", bodyMatcher);
|
|
179
|
+
}
|
|
180
|
+
function recordCall(callHistory, request, bodyText) {
|
|
181
|
+
const url = new URL(request.url);
|
|
182
|
+
const requestHeaders = {};
|
|
183
|
+
request.headers.forEach((value, key) => {
|
|
184
|
+
requestHeaders[key] = value;
|
|
185
|
+
});
|
|
186
|
+
const searchParams = {};
|
|
187
|
+
url.searchParams.forEach((value, key) => {
|
|
188
|
+
searchParams[key] = value;
|
|
189
|
+
});
|
|
190
|
+
callHistory.record({
|
|
191
|
+
body: bodyText,
|
|
192
|
+
method: request.method,
|
|
193
|
+
headers: requestHeaders,
|
|
194
|
+
fullUrl: url.origin + url.pathname + url.search,
|
|
195
|
+
origin: url.origin,
|
|
196
|
+
path: url.pathname,
|
|
197
|
+
searchParams,
|
|
198
|
+
protocol: url.protocol,
|
|
199
|
+
host: url.host,
|
|
200
|
+
port: url.port,
|
|
201
|
+
hash: url.hash
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/type-guards.ts
|
|
206
|
+
function isSetupServerLike(input) {
|
|
207
|
+
return typeof input === "object" && input !== null && "listen" in input && typeof input.listen === "function" && "close" in input && typeof input.close === "function";
|
|
208
|
+
}
|
|
209
|
+
function isSetupWorkerLike(input) {
|
|
210
|
+
return typeof input === "object" && input !== null && "start" in input && typeof input.start === "function" && "stop" in input && typeof input.stop === "function";
|
|
211
|
+
}
|
|
212
|
+
function isMswAdapter(input) {
|
|
213
|
+
return typeof input === "object" && input !== null && "activate" in input && typeof input.activate === "function" && "deactivate" in input && typeof input.deactivate === "function";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/fetch-mock.ts
|
|
217
|
+
function createServerAdapter(server) {
|
|
218
|
+
return {
|
|
219
|
+
use: (...handlers) => server.use(...handlers),
|
|
220
|
+
resetHandlers: (...handlers) => server.resetHandlers(...handlers),
|
|
221
|
+
activate(options) {
|
|
222
|
+
server.listen({ onUnhandledRequest: options.onUnhandledRequest });
|
|
223
|
+
},
|
|
224
|
+
deactivate() {
|
|
225
|
+
server.close();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function createWorkerAdapter(worker) {
|
|
230
|
+
return {
|
|
231
|
+
use: (...handlers) => worker.use(...handlers),
|
|
232
|
+
resetHandlers: (...handlers) => worker.resetHandlers(...handlers),
|
|
233
|
+
async activate(options) {
|
|
234
|
+
await worker.start({ onUnhandledRequest: options.onUnhandledRequest });
|
|
235
|
+
},
|
|
236
|
+
deactivate() {
|
|
237
|
+
worker.stop();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function resolveAdapter(input) {
|
|
242
|
+
if (!input) {
|
|
243
|
+
if (!FetchMock._defaultAdapterFactory) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
"FetchMock requires a server, worker, or adapter argument. Use createFetchMock() from msw-fetch-mock/node or msw-fetch-mock/browser, or pass a setupServer/setupWorker instance directly."
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return FetchMock._defaultAdapterFactory();
|
|
249
|
+
}
|
|
250
|
+
if (isMswAdapter(input)) return input;
|
|
251
|
+
if (isSetupServerLike(input)) return createServerAdapter(input);
|
|
252
|
+
if (isSetupWorkerLike(input)) return createWorkerAdapter(input);
|
|
253
|
+
throw new Error("Invalid argument: expected a setupServer, setupWorker, or MswAdapter instance.");
|
|
254
|
+
}
|
|
255
|
+
var FetchMock = class _FetchMock {
|
|
256
|
+
/** @internal */
|
|
257
|
+
static _defaultAdapterFactory;
|
|
258
|
+
/** @internal */
|
|
259
|
+
static _handlerFactory;
|
|
260
|
+
get handlerFactory() {
|
|
261
|
+
if (!_FetchMock._handlerFactory) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
"Handler factory not registered. Import from msw-fetch-mock/node or msw-fetch-mock/browser."
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
return _FetchMock._handlerFactory;
|
|
267
|
+
}
|
|
268
|
+
buildResponse(status, responseBody, replyOptions, defaultHeaders, addContentLength) {
|
|
269
|
+
const mergedHeaders = { ...defaultHeaders };
|
|
270
|
+
if (replyOptions?.headers) {
|
|
271
|
+
Object.assign(mergedHeaders, replyOptions.headers);
|
|
272
|
+
}
|
|
273
|
+
if (addContentLength && responseBody !== null && responseBody !== void 0) {
|
|
274
|
+
mergedHeaders["Content-Length"] = String(JSON.stringify(responseBody).length);
|
|
275
|
+
}
|
|
276
|
+
const headers = Object.keys(mergedHeaders).length > 0 ? new Headers(mergedHeaders) : void 0;
|
|
277
|
+
return this.handlerFactory.buildResponse(status, responseBody, headers);
|
|
278
|
+
}
|
|
279
|
+
_calls = new MockCallHistory();
|
|
280
|
+
adapter;
|
|
281
|
+
interceptors = [];
|
|
282
|
+
netConnectAllowed = false;
|
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
284
|
+
mswHandlers = /* @__PURE__ */ new Map();
|
|
285
|
+
_defaultReplyHeaders = {};
|
|
286
|
+
_callHistoryEnabled = true;
|
|
287
|
+
get calls() {
|
|
288
|
+
return this._calls;
|
|
289
|
+
}
|
|
290
|
+
constructor(input) {
|
|
291
|
+
this.adapter = resolveAdapter(input);
|
|
292
|
+
}
|
|
293
|
+
async activate(options) {
|
|
294
|
+
const mode = options?.onUnhandledRequest ?? "error";
|
|
295
|
+
await this.adapter.activate({
|
|
296
|
+
onUnhandledRequest: (request, print) => {
|
|
297
|
+
if (this.isNetConnectAllowed(request)) return;
|
|
298
|
+
if (typeof mode === "function") {
|
|
299
|
+
mode(request, print);
|
|
300
|
+
} else if (mode === "error") {
|
|
301
|
+
print.error();
|
|
302
|
+
} else if (mode === "warn") {
|
|
303
|
+
print.warning();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
disableNetConnect() {
|
|
309
|
+
this.netConnectAllowed = false;
|
|
310
|
+
}
|
|
311
|
+
enableNetConnect(matcher) {
|
|
312
|
+
this.netConnectAllowed = matcher ?? true;
|
|
313
|
+
}
|
|
314
|
+
isNetConnectAllowed(request) {
|
|
315
|
+
if (this.netConnectAllowed === true) return true;
|
|
316
|
+
if (this.netConnectAllowed === false) return false;
|
|
317
|
+
const host = new URL(request.url).host;
|
|
318
|
+
if (typeof this.netConnectAllowed === "string") return host === this.netConnectAllowed;
|
|
319
|
+
if (this.netConnectAllowed instanceof RegExp) return this.netConnectAllowed.test(host);
|
|
320
|
+
return this.netConnectAllowed(host);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Remove consumed MSW handlers so future requests to those URLs
|
|
324
|
+
* go through MSW's onUnhandledRequest instead of silently passing through.
|
|
325
|
+
*/
|
|
326
|
+
syncMswHandlers() {
|
|
327
|
+
const activeHandlers = [...this.mswHandlers.entries()].filter(([p]) => !p.consumed || p.persist).map(([, handler]) => handler);
|
|
328
|
+
this.adapter.resetHandlers(...activeHandlers);
|
|
329
|
+
}
|
|
330
|
+
getCallHistory() {
|
|
331
|
+
return this._calls;
|
|
332
|
+
}
|
|
333
|
+
clearCallHistory() {
|
|
334
|
+
this._calls.clear();
|
|
335
|
+
}
|
|
336
|
+
clearAllCallHistory() {
|
|
337
|
+
this.clearCallHistory();
|
|
338
|
+
}
|
|
339
|
+
defaultReplyHeaders(headers) {
|
|
340
|
+
this._defaultReplyHeaders = headers;
|
|
341
|
+
}
|
|
342
|
+
enableCallHistory() {
|
|
343
|
+
this._callHistoryEnabled = true;
|
|
344
|
+
}
|
|
345
|
+
disableCallHistory() {
|
|
346
|
+
this._callHistoryEnabled = false;
|
|
347
|
+
}
|
|
348
|
+
deactivate() {
|
|
349
|
+
this.interceptors = [];
|
|
350
|
+
this.mswHandlers.clear();
|
|
351
|
+
this._calls.clear();
|
|
352
|
+
this.adapter.deactivate();
|
|
353
|
+
}
|
|
354
|
+
reset() {
|
|
355
|
+
this.interceptors = [];
|
|
356
|
+
this.mswHandlers.clear();
|
|
357
|
+
this._calls.clear();
|
|
358
|
+
this._defaultReplyHeaders = {};
|
|
359
|
+
this.adapter.resetHandlers();
|
|
360
|
+
}
|
|
361
|
+
assertNoPendingInterceptors() {
|
|
362
|
+
const unconsumed = this.interceptors.filter(isPending);
|
|
363
|
+
if (unconsumed.length > 0) {
|
|
364
|
+
const descriptions = unconsumed.map((p) => ` ${p.method} ${p.origin}${p.path}`);
|
|
365
|
+
throw new Error(`Pending interceptor(s) not consumed:
|
|
366
|
+
${descriptions.join("\n")}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
pendingInterceptors() {
|
|
370
|
+
return this.interceptors.filter(isPending).map((p) => ({ ...p }));
|
|
371
|
+
}
|
|
372
|
+
resolveUrlPattern(origin, path) {
|
|
373
|
+
if (typeof origin === "string") {
|
|
374
|
+
return typeof path === "string" ? `${origin}${path}` : new RegExp(`^${escapeRegExp(origin)}`);
|
|
375
|
+
}
|
|
376
|
+
return /.*/;
|
|
377
|
+
}
|
|
378
|
+
matchOriginAndPath(request, origin, originStr, path) {
|
|
379
|
+
if (typeof origin === "string") {
|
|
380
|
+
return matchPath(request, originStr, path);
|
|
381
|
+
}
|
|
382
|
+
const url = new URL(request.url);
|
|
383
|
+
if (origin instanceof RegExp ? !origin.test(url.origin) : !origin(url.origin)) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
if (typeof path === "string") {
|
|
387
|
+
return url.pathname === path || url.pathname.endsWith(path);
|
|
388
|
+
}
|
|
389
|
+
const fullPath = url.pathname + url.search;
|
|
390
|
+
return matchesValue(fullPath, path);
|
|
391
|
+
}
|
|
392
|
+
async matchAndConsume(request, pending, origin, originStr, options) {
|
|
393
|
+
if (!pending.persist && pending.timesInvoked >= pending.times) return;
|
|
394
|
+
if (!this.matchOriginAndPath(request, origin, originStr, options.path)) return;
|
|
395
|
+
if (!matchQuery(request, options.query)) return;
|
|
396
|
+
if (!matchHeaders(request, options.headers)) return;
|
|
397
|
+
const bodyText = await request.text() || null;
|
|
398
|
+
if (!matchBody(bodyText, options.body)) return;
|
|
399
|
+
pending.timesInvoked++;
|
|
400
|
+
if (!pending.persist && pending.timesInvoked >= pending.times) {
|
|
401
|
+
pending.consumed = true;
|
|
402
|
+
this.syncMswHandlers();
|
|
403
|
+
}
|
|
404
|
+
if (this._callHistoryEnabled) {
|
|
405
|
+
recordCall(this._calls, request, bodyText);
|
|
406
|
+
}
|
|
407
|
+
return bodyText;
|
|
408
|
+
}
|
|
409
|
+
registerHandler(pending, method, urlPattern, handlerFn) {
|
|
410
|
+
const handler = this.handlerFactory.createHandler(method, urlPattern, handlerFn);
|
|
411
|
+
this.mswHandlers.set(pending, handler);
|
|
412
|
+
this.adapter.use(handler);
|
|
413
|
+
}
|
|
414
|
+
createMatchingHandler(pending, origin, originStr, options, delayRef, respond) {
|
|
415
|
+
return async (request) => {
|
|
416
|
+
const bodyText = await this.matchAndConsume(request, pending, origin, originStr, options);
|
|
417
|
+
if (bodyText === void 0) return;
|
|
418
|
+
if (delayRef.ms > 0) {
|
|
419
|
+
await new Promise((resolve) => setTimeout(resolve, delayRef.ms));
|
|
420
|
+
}
|
|
421
|
+
return respond(bodyText);
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
buildChain(pending, delayRef, contentLengthRef) {
|
|
425
|
+
return {
|
|
426
|
+
times(n) {
|
|
427
|
+
pending.times = n;
|
|
428
|
+
pending.consumed = false;
|
|
429
|
+
},
|
|
430
|
+
persist() {
|
|
431
|
+
pending.persist = true;
|
|
432
|
+
pending.consumed = false;
|
|
433
|
+
},
|
|
434
|
+
delay(ms) {
|
|
435
|
+
delayRef.ms = ms;
|
|
436
|
+
},
|
|
437
|
+
replyContentLength() {
|
|
438
|
+
contentLengthRef.enabled = true;
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
get(origin) {
|
|
443
|
+
const originStr = typeof origin === "string" ? origin : origin instanceof RegExp ? origin.toString() : "<function>";
|
|
444
|
+
return {
|
|
445
|
+
intercept: (options) => {
|
|
446
|
+
const method = options.method ?? "GET";
|
|
447
|
+
const pathStr = typeof options.path === "string" ? options.path : typeof options.path === "function" ? "<function>" : options.path.toString();
|
|
448
|
+
const pending = {
|
|
449
|
+
origin: originStr,
|
|
450
|
+
path: pathStr,
|
|
451
|
+
method,
|
|
452
|
+
consumed: false,
|
|
453
|
+
times: 1,
|
|
454
|
+
timesInvoked: 0,
|
|
455
|
+
persist: false
|
|
456
|
+
};
|
|
457
|
+
this.interceptors.push(pending);
|
|
458
|
+
const urlPattern = this.resolveUrlPattern(origin, options.path);
|
|
459
|
+
return {
|
|
460
|
+
reply: (statusOrCallback, bodyOrCallback, replyOptions) => {
|
|
461
|
+
const delayRef = { ms: 0 };
|
|
462
|
+
const contentLengthRef = { enabled: false };
|
|
463
|
+
if (typeof statusOrCallback === "function") {
|
|
464
|
+
const callback = statusOrCallback;
|
|
465
|
+
this.registerHandler(
|
|
466
|
+
pending,
|
|
467
|
+
method,
|
|
468
|
+
urlPattern,
|
|
469
|
+
this.createMatchingHandler(
|
|
470
|
+
pending,
|
|
471
|
+
origin,
|
|
472
|
+
originStr,
|
|
473
|
+
options,
|
|
474
|
+
delayRef,
|
|
475
|
+
async (bodyText) => {
|
|
476
|
+
const result = await callback({ body: bodyText });
|
|
477
|
+
return this.buildResponse(
|
|
478
|
+
result.statusCode,
|
|
479
|
+
result.data,
|
|
480
|
+
result.responseOptions,
|
|
481
|
+
this._defaultReplyHeaders,
|
|
482
|
+
contentLengthRef.enabled
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
)
|
|
486
|
+
);
|
|
487
|
+
} else {
|
|
488
|
+
const status = statusOrCallback;
|
|
489
|
+
this.registerHandler(
|
|
490
|
+
pending,
|
|
491
|
+
method,
|
|
492
|
+
urlPattern,
|
|
493
|
+
this.createMatchingHandler(
|
|
494
|
+
pending,
|
|
495
|
+
origin,
|
|
496
|
+
originStr,
|
|
497
|
+
options,
|
|
498
|
+
delayRef,
|
|
499
|
+
async (bodyText) => {
|
|
500
|
+
let responseBody;
|
|
501
|
+
if (typeof bodyOrCallback === "function") {
|
|
502
|
+
responseBody = await bodyOrCallback({
|
|
503
|
+
body: bodyText
|
|
504
|
+
});
|
|
505
|
+
} else {
|
|
506
|
+
responseBody = bodyOrCallback;
|
|
507
|
+
}
|
|
508
|
+
return this.buildResponse(
|
|
509
|
+
status,
|
|
510
|
+
responseBody,
|
|
511
|
+
replyOptions,
|
|
512
|
+
this._defaultReplyHeaders,
|
|
513
|
+
contentLengthRef.enabled
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
)
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
return this.buildChain(pending, delayRef, contentLengthRef);
|
|
520
|
+
},
|
|
521
|
+
replyWithError: () => {
|
|
522
|
+
const delayRef = { ms: 0 };
|
|
523
|
+
const contentLengthRef = { enabled: false };
|
|
524
|
+
this.registerHandler(
|
|
525
|
+
pending,
|
|
526
|
+
method,
|
|
527
|
+
urlPattern,
|
|
528
|
+
this.createMatchingHandler(
|
|
529
|
+
pending,
|
|
530
|
+
origin,
|
|
531
|
+
originStr,
|
|
532
|
+
options,
|
|
533
|
+
delayRef,
|
|
534
|
+
async () => {
|
|
535
|
+
return this.handlerFactory.buildErrorResponse();
|
|
536
|
+
}
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
return this.buildChain(pending, delayRef, contentLengthRef);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
export {
|
|
548
|
+
MockCallHistoryLog,
|
|
549
|
+
MockCallHistory,
|
|
550
|
+
FetchMock
|
|
551
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/http-handler-factory.ts
|
|
2
|
+
import { http, HttpResponse } from "msw";
|
|
3
|
+
var methods = {
|
|
4
|
+
GET: http.get,
|
|
5
|
+
POST: http.post,
|
|
6
|
+
PUT: http.put,
|
|
7
|
+
DELETE: http.delete,
|
|
8
|
+
PATCH: http.patch
|
|
9
|
+
};
|
|
10
|
+
var httpHandlerFactory = {
|
|
11
|
+
createHandler(method, urlPattern, handlerFn) {
|
|
12
|
+
return methods[method](urlPattern, async ({ request }) => handlerFn(request));
|
|
13
|
+
},
|
|
14
|
+
buildResponse(status, body, headers) {
|
|
15
|
+
if (body === null || body === void 0) {
|
|
16
|
+
return new HttpResponse(null, { status, headers });
|
|
17
|
+
}
|
|
18
|
+
return HttpResponse.json(body, { status, headers });
|
|
19
|
+
},
|
|
20
|
+
buildErrorResponse() {
|
|
21
|
+
return HttpResponse.error();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
httpHandlerFactory
|
|
27
|
+
};
|