@mswjs/interceptors 0.32.1 → 0.33.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.
- package/README.md +35 -7
- package/lib/browser/{chunk-732REFPX.mjs → chunk-5ETVT6GU.mjs} +28 -79
- package/lib/browser/chunk-5ETVT6GU.mjs.map +1 -0
- package/lib/browser/chunk-6MBJUL74.js +142 -0
- package/lib/browser/chunk-6MBJUL74.js.map +1 -0
- package/lib/browser/chunk-7A4UJNSW.mjs +196 -0
- package/lib/browser/chunk-7A4UJNSW.mjs.map +1 -0
- package/lib/browser/{chunk-PSX5J3RF.js → chunk-7GVJEW45.js} +30 -81
- package/lib/browser/chunk-7GVJEW45.js.map +1 -0
- package/lib/browser/{chunk-2CRB3JAQ.js → chunk-FXSPMSSQ.js} +1 -1
- package/lib/browser/chunk-FXSPMSSQ.js.map +1 -0
- package/lib/browser/{chunk-OMISYKWR.mjs → chunk-GGUENBDN.mjs} +1 -1
- package/lib/browser/chunk-GGUENBDN.mjs.map +1 -0
- package/lib/browser/chunk-NU2MPFD6.mjs +142 -0
- package/lib/browser/chunk-NU2MPFD6.mjs.map +1 -0
- package/lib/browser/chunk-VRKVKT62.js +196 -0
- package/lib/browser/chunk-VRKVKT62.js.map +1 -0
- package/lib/browser/glossary-7d7adb4b.d.ts +66 -0
- package/lib/browser/index.d.ts +1 -1
- package/lib/browser/index.js +2 -2
- package/lib/browser/index.mjs +1 -1
- package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +2 -6
- package/lib/browser/interceptors/XMLHttpRequest/index.js +4 -4
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +3 -3
- package/lib/browser/interceptors/fetch/index.d.ts +1 -1
- package/lib/browser/interceptors/fetch/index.js +4 -4
- package/lib/browser/interceptors/fetch/index.mjs +3 -3
- package/lib/browser/presets/browser.d.ts +1 -1
- package/lib/browser/presets/browser.js +6 -6
- package/lib/browser/presets/browser.mjs +4 -4
- package/lib/node/{BatchInterceptor-2badedde.d.ts → BatchInterceptor-13d40c95.d.ts} +1 -1
- package/lib/node/{Interceptor-88ee47c0.d.ts → Interceptor-a31b1217.d.ts} +35 -13
- package/lib/node/RemoteHttpInterceptor.d.ts +2 -2
- package/lib/node/RemoteHttpInterceptor.js +55 -52
- package/lib/node/RemoteHttpInterceptor.js.map +1 -1
- package/lib/node/RemoteHttpInterceptor.mjs +53 -50
- package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
- package/lib/node/{chunk-5JMJ55U7.js → chunk-2MWIWEWV.js} +144 -113
- package/lib/node/chunk-2MWIWEWV.js.map +1 -0
- package/lib/node/{chunk-2COJKQQB.js → chunk-42632LKH.js} +3 -3
- package/lib/node/chunk-5WWNCLB3.js +196 -0
- package/lib/node/chunk-5WWNCLB3.js.map +1 -0
- package/lib/node/{chunk-TGTPXCLF.mjs → chunk-BUCULLYM.mjs} +1 -1
- package/lib/node/{chunk-TGTPXCLF.mjs.map → chunk-BUCULLYM.mjs.map} +1 -1
- package/lib/node/{chunk-OJ6O4LSC.mjs → chunk-BZ3Y7YV5.mjs} +1 -1
- package/lib/node/chunk-BZ3Y7YV5.mjs.map +1 -0
- package/lib/node/{chunk-3OJLYEWA.mjs → chunk-CU3YXMM4.mjs} +138 -107
- package/lib/node/chunk-CU3YXMM4.mjs.map +1 -0
- package/lib/node/{chunk-PNWPIDEL.mjs → chunk-HGQLG7KE.mjs} +2 -2
- package/lib/node/{chunk-EIBTX65O.js → chunk-IDEEMJ3F.js} +1 -1
- package/lib/node/chunk-IDEEMJ3F.js.map +1 -0
- package/lib/node/chunk-KY3RJ2M3.mjs +196 -0
- package/lib/node/chunk-KY3RJ2M3.mjs.map +1 -0
- package/lib/node/{chunk-PYD4E2EJ.js → chunk-P6QG76R3.js} +34 -85
- package/lib/node/chunk-P6QG76R3.js.map +1 -0
- package/lib/node/{chunk-DV4PBH4D.mjs → chunk-TOV4TYIX.mjs} +29 -80
- package/lib/node/chunk-TOV4TYIX.mjs.map +1 -0
- package/lib/node/{chunk-BFLYGQ6D.js → chunk-YGM3BCJU.js} +1 -1
- package/lib/node/chunk-YGM3BCJU.js.map +1 -0
- package/lib/node/index.d.ts +2 -2
- package/lib/node/index.js +4 -4
- package/lib/node/index.mjs +3 -3
- package/lib/node/interceptors/ClientRequest/index.d.ts +2 -2
- package/lib/node/interceptors/ClientRequest/index.js +4 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
- package/lib/node/interceptors/XMLHttpRequest/index.d.ts +2 -6
- package/lib/node/interceptors/XMLHttpRequest/index.js +5 -5
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +4 -4
- package/lib/node/interceptors/fetch/index.d.ts +1 -1
- package/lib/node/interceptors/fetch/index.js +52 -123
- package/lib/node/interceptors/fetch/index.js.map +1 -1
- package/lib/node/interceptors/fetch/index.mjs +50 -121
- package/lib/node/interceptors/fetch/index.mjs.map +1 -1
- package/lib/node/presets/node.d.ts +1 -1
- package/lib/node/presets/node.js +7 -7
- package/lib/node/presets/node.mjs +5 -5
- package/package.json +2 -2
- package/src/InterceptorError.ts +7 -0
- package/src/RemoteHttpInterceptor.ts +62 -57
- package/src/RequestController.test.ts +49 -0
- package/src/RequestController.ts +81 -0
- package/src/glossary.ts +4 -6
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +22 -16
- package/src/interceptors/ClientRequest/index.test.ts +2 -33
- package/src/interceptors/ClientRequest/index.ts +32 -82
- package/src/interceptors/ClientRequest/utils/recordRawHeaders.ts +170 -0
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +1 -1
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +27 -108
- package/src/interceptors/XMLHttpRequest/index.ts +0 -6
- package/src/interceptors/fetch/index.ts +52 -169
- package/src/utils/handleRequest.ts +213 -0
- package/src/utils/responseUtils.ts +4 -4
- package/lib/browser/chunk-2CRB3JAQ.js.map +0 -1
- package/lib/browser/chunk-732REFPX.mjs.map +0 -1
- package/lib/browser/chunk-MAEPOYB6.mjs +0 -213
- package/lib/browser/chunk-MAEPOYB6.mjs.map +0 -1
- package/lib/browser/chunk-MQJ3JOOK.js +0 -49
- package/lib/browser/chunk-MQJ3JOOK.js.map +0 -1
- package/lib/browser/chunk-OMISYKWR.mjs.map +0 -1
- package/lib/browser/chunk-OUWBQF3Z.mjs +0 -49
- package/lib/browser/chunk-OUWBQF3Z.mjs.map +0 -1
- package/lib/browser/chunk-PSX5J3RF.js.map +0 -1
- package/lib/browser/chunk-WBHIW62P.js +0 -213
- package/lib/browser/chunk-WBHIW62P.js.map +0 -1
- package/lib/browser/glossary-1c204f45.d.ts +0 -44
- package/lib/node/chunk-3OJLYEWA.mjs.map +0 -1
- package/lib/node/chunk-5JMJ55U7.js.map +0 -1
- package/lib/node/chunk-BFLYGQ6D.js.map +0 -1
- package/lib/node/chunk-DV4PBH4D.mjs.map +0 -1
- package/lib/node/chunk-EIBTX65O.js.map +0 -1
- package/lib/node/chunk-KWV3JXSI.mjs +0 -49
- package/lib/node/chunk-KWV3JXSI.mjs.map +0 -1
- package/lib/node/chunk-OJ6O4LSC.mjs.map +0 -1
- package/lib/node/chunk-PYD4E2EJ.js.map +0 -1
- package/lib/node/chunk-UXCYRE4F.js +0 -49
- package/lib/node/chunk-UXCYRE4F.js.map +0 -1
- package/src/utils/getRawFetchHeaders.test.ts +0 -50
- package/src/utils/getRawFetchHeaders.ts +0 -56
- package/src/utils/toInteractiveRequest.ts +0 -23
- /package/lib/node/{chunk-2COJKQQB.js.map → chunk-42632LKH.js.map} +0 -0
- /package/lib/node/{chunk-PNWPIDEL.mjs.map → chunk-HGQLG7KE.mjs.map} +0 -0
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkIDEEMJ3Fjs = require('../../chunk-IDEEMJ3F.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var _chunkUXCYRE4Fjs = require('../../chunk-UXCYRE4F.js');
|
|
8
7
|
|
|
8
|
+
var _chunk5WWNCLB3js = require('../../chunk-5WWNCLB3.js');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
var _chunkBFLYGQ6Djs = require('../../chunk-BFLYGQ6D.js');
|
|
12
|
+
var _chunkYGM3BCJUjs = require('../../chunk-YGM3BCJU.js');
|
|
14
13
|
|
|
15
14
|
// src/interceptors/fetch/index.ts
|
|
16
15
|
var _outvariant = require('outvariant');
|
|
17
16
|
var _deferredpromise = require('@open-draft/deferred-promise');
|
|
18
|
-
var _until = require('@open-draft/until');
|
|
19
17
|
|
|
20
18
|
// src/utils/canParseUrl.ts
|
|
21
19
|
function canParseUrl(url) {
|
|
@@ -28,7 +26,7 @@ function canParseUrl(url) {
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
// src/interceptors/fetch/index.ts
|
|
31
|
-
var _FetchInterceptor = class extends
|
|
29
|
+
var _FetchInterceptor = class extends _chunkYGM3BCJUjs.Interceptor {
|
|
32
30
|
constructor() {
|
|
33
31
|
super(_FetchInterceptor.symbol);
|
|
34
32
|
}
|
|
@@ -38,135 +36,66 @@ var _FetchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
|
|
|
38
36
|
async setup() {
|
|
39
37
|
const pureFetch = globalThis.fetch;
|
|
40
38
|
_outvariant.invariant.call(void 0,
|
|
41
|
-
!pureFetch[
|
|
39
|
+
!pureFetch[_chunkIDEEMJ3Fjs.IS_PATCHED_MODULE],
|
|
42
40
|
'Failed to patch the "fetch" module: already patched.'
|
|
43
41
|
);
|
|
44
42
|
globalThis.fetch = async (input, init) => {
|
|
45
|
-
|
|
46
|
-
const requestId = _chunkBFLYGQ6Djs.createRequestId.call(void 0, );
|
|
43
|
+
const requestId = _chunkYGM3BCJUjs.createRequestId.call(void 0, );
|
|
47
44
|
const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input;
|
|
48
45
|
const request = new Request(resolvedInput, init);
|
|
46
|
+
const responsePromise = new (0, _deferredpromise.DeferredPromise)();
|
|
47
|
+
const controller = new (0, _chunk5WWNCLB3js.RequestController)(request);
|
|
49
48
|
this.logger.info("[%s] %s", request.method, request.url);
|
|
50
|
-
|
|
49
|
+
this.logger.info("awaiting for the mocked response...");
|
|
51
50
|
this.logger.info(
|
|
52
|
-
'emitting the "request" event for %
|
|
51
|
+
'emitting the "request" event for %s listener(s)...',
|
|
53
52
|
this.emitter.listenerCount("request")
|
|
54
53
|
);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.logger.info("awaiting for the mocked response...");
|
|
64
|
-
const signal = interactiveRequest.signal;
|
|
65
|
-
const requestAborted = new (0, _deferredpromise.DeferredPromise)();
|
|
66
|
-
if (signal) {
|
|
67
|
-
signal.addEventListener(
|
|
68
|
-
"abort",
|
|
69
|
-
() => {
|
|
70
|
-
requestAborted.reject(signal.reason);
|
|
71
|
-
},
|
|
72
|
-
{ once: true }
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
const responsePromise = new (0, _deferredpromise.DeferredPromise)();
|
|
76
|
-
const respondWith = (response) => {
|
|
77
|
-
this.logger.info("responding with a mock response:", response);
|
|
78
|
-
if (this.emitter.listenerCount("response") > 0) {
|
|
79
|
-
this.logger.info('emitting the "response" event...');
|
|
80
|
-
const responseClone = response.clone();
|
|
81
|
-
this.emitter.emit("response", {
|
|
82
|
-
response: responseClone,
|
|
83
|
-
isMockedResponse: true,
|
|
84
|
-
request: interactiveRequest,
|
|
85
|
-
requestId
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
Object.defineProperty(response, "url", {
|
|
89
|
-
writable: false,
|
|
90
|
-
enumerable: true,
|
|
91
|
-
configurable: false,
|
|
92
|
-
value: request.url
|
|
93
|
-
});
|
|
94
|
-
responsePromise.resolve(response);
|
|
95
|
-
};
|
|
96
|
-
const errorWith = (reason) => {
|
|
97
|
-
responsePromise.reject(reason);
|
|
98
|
-
};
|
|
99
|
-
const resolverResult = await _until.until.call(void 0,
|
|
100
|
-
async () => {
|
|
101
|
-
const listenersFinished = _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "request", {
|
|
102
|
-
request: interactiveRequest,
|
|
103
|
-
requestId
|
|
54
|
+
const isRequestHandled = await _chunk5WWNCLB3js.handleRequest.call(void 0, {
|
|
55
|
+
request,
|
|
56
|
+
requestId,
|
|
57
|
+
emitter: this.emitter,
|
|
58
|
+
controller,
|
|
59
|
+
onResponse: async (response) => {
|
|
60
|
+
this.logger.info("received mocked response!", {
|
|
61
|
+
response
|
|
104
62
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return mockedResponse2;
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
if (requestAborted.state === "rejected") {
|
|
120
|
-
this.logger.info(
|
|
121
|
-
"request has been aborted:",
|
|
122
|
-
requestAborted.rejectionReason
|
|
123
|
-
);
|
|
124
|
-
responsePromise.reject(requestAborted.rejectionReason);
|
|
125
|
-
return responsePromise;
|
|
126
|
-
}
|
|
127
|
-
if (resolverResult.error) {
|
|
128
|
-
this.logger.info(
|
|
129
|
-
"request listerner threw an error:",
|
|
130
|
-
resolverResult.error
|
|
131
|
-
);
|
|
132
|
-
if (resolverResult.error instanceof Response) {
|
|
133
|
-
if (_chunkBFLYGQ6Djs.isResponseError.call(void 0, resolverResult.error)) {
|
|
134
|
-
errorWith(createNetworkError(resolverResult.error));
|
|
135
|
-
} else {
|
|
136
|
-
respondWith(resolverResult.error);
|
|
63
|
+
if (this.emitter.listenerCount("response") > 0) {
|
|
64
|
+
this.logger.info('emitting the "response" event...');
|
|
65
|
+
await _chunk5WWNCLB3js.emitAsync.call(void 0, this.emitter, "response", {
|
|
66
|
+
// Clone the mocked response for the "response" event listener.
|
|
67
|
+
// This way, the listener can read the response and not lock its body
|
|
68
|
+
// for the actual fetch consumer.
|
|
69
|
+
response: response.clone(),
|
|
70
|
+
isMockedResponse: true,
|
|
71
|
+
request,
|
|
72
|
+
requestId
|
|
73
|
+
});
|
|
137
74
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
request
|
|
143
|
-
requestId,
|
|
144
|
-
controller: {
|
|
145
|
-
respondWith,
|
|
146
|
-
errorWith
|
|
147
|
-
}
|
|
75
|
+
Object.defineProperty(response, "url", {
|
|
76
|
+
writable: false,
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: false,
|
|
79
|
+
value: request.url
|
|
148
80
|
});
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.logger.info("received mocked response:", mockedResponse);
|
|
159
|
-
if (_chunkBFLYGQ6Djs.isResponseError.call(void 0, mockedResponse)) {
|
|
160
|
-
this.logger.info(
|
|
161
|
-
"received a network error response, rejecting the request promise..."
|
|
162
|
-
);
|
|
163
|
-
errorWith(createNetworkError(mockedResponse));
|
|
164
|
-
} else {
|
|
165
|
-
respondWith(mockedResponse);
|
|
81
|
+
responsePromise.resolve(response);
|
|
82
|
+
},
|
|
83
|
+
onRequestError: (response) => {
|
|
84
|
+
this.logger.info("request has errored!", { response });
|
|
85
|
+
responsePromise.reject(createNetworkError(response));
|
|
86
|
+
},
|
|
87
|
+
onError: (error) => {
|
|
88
|
+
this.logger.info("request has been aborted!", { error });
|
|
89
|
+
responsePromise.reject(error);
|
|
166
90
|
}
|
|
91
|
+
});
|
|
92
|
+
if (isRequestHandled) {
|
|
93
|
+
this.logger.info("request has been handled, returning mock promise...");
|
|
167
94
|
return responsePromise;
|
|
168
95
|
}
|
|
169
|
-
this.logger.info(
|
|
96
|
+
this.logger.info(
|
|
97
|
+
"no mocked response received, performing request as-is..."
|
|
98
|
+
);
|
|
170
99
|
return pureFetch(request).then((response) => {
|
|
171
100
|
this.logger.info("original fetch performed", response);
|
|
172
101
|
if (this.emitter.listenerCount("response") > 0) {
|
|
@@ -175,20 +104,20 @@ var _FetchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
|
|
|
175
104
|
this.emitter.emit("response", {
|
|
176
105
|
response: responseClone,
|
|
177
106
|
isMockedResponse: false,
|
|
178
|
-
request
|
|
107
|
+
request,
|
|
179
108
|
requestId
|
|
180
109
|
});
|
|
181
110
|
}
|
|
182
111
|
return response;
|
|
183
112
|
});
|
|
184
113
|
};
|
|
185
|
-
Object.defineProperty(globalThis.fetch,
|
|
114
|
+
Object.defineProperty(globalThis.fetch, _chunkIDEEMJ3Fjs.IS_PATCHED_MODULE, {
|
|
186
115
|
enumerable: true,
|
|
187
116
|
configurable: true,
|
|
188
117
|
value: true
|
|
189
118
|
});
|
|
190
119
|
this.subscriptions.push(() => {
|
|
191
|
-
Object.defineProperty(globalThis.fetch,
|
|
120
|
+
Object.defineProperty(globalThis.fetch, _chunkIDEEMJ3Fjs.IS_PATCHED_MODULE, {
|
|
192
121
|
value: void 0
|
|
193
122
|
});
|
|
194
123
|
globalThis.fetch = pureFetch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"names":["mockedResponse"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport {\n createServerErrorResponse,\n isResponseError,\n} from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const responsePromise = new DeferredPromise<Response>()\n\n const respondWith = (response: Response): void => {\n this.logger.info('responding with a mock response:', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n }\n\n const errorWith = (reason: unknown): void => {\n responsePromise.reject(reason)\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n this.logger.info(\n 'request has been aborted:',\n requestAborted.rejectionReason\n )\n\n responsePromise.reject(requestAborted.rejectionReason)\n return responsePromise\n }\n\n if (resolverResult.error) {\n this.logger.info(\n 'request listerner threw an error:',\n resolverResult.error\n )\n\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n // Treat thrown Response.error() as a request error.\n if (isResponseError(resolverResult.error)) {\n errorWith(createNetworkError(resolverResult.error))\n } else {\n // Treat the rest of thrown Responses as mocked responses.\n respondWith(resolverResult.error)\n }\n }\n\n // Emit the \"unhandledException\" interceptor event so the client\n // can opt-out from exceptions translating to 500 error responses.\n\n if (this.emitter.listenerCount('unhandledException') > 0) {\n await emitAsync(this.emitter, 'unhandledException', {\n error: resolverResult.error,\n request,\n requestId,\n controller: {\n respondWith,\n errorWith,\n },\n })\n\n if (responsePromise.state !== 'pending') {\n return responsePromise\n }\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n respondWith(createServerErrorResponse(resolverResult.error))\n return responsePromise\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (isResponseError(mockedResponse)) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n errorWith(createNetworkError(mockedResponse))\n } else {\n respondWith(mockedResponse)\n }\n\n return responsePromise\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"names":[],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise<Response>()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (response) => {\n this.logger.info('received mocked response!', {\n response,\n })\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"]}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IS_PATCHED_MODULE
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-BZ3Y7YV5.mjs";
|
|
4
4
|
import {
|
|
5
|
+
RequestController,
|
|
5
6
|
emitAsync,
|
|
6
|
-
|
|
7
|
-
} from "../../chunk-
|
|
7
|
+
handleRequest
|
|
8
|
+
} from "../../chunk-KY3RJ2M3.mjs";
|
|
8
9
|
import {
|
|
9
10
|
Interceptor,
|
|
10
|
-
createRequestId
|
|
11
|
-
|
|
12
|
-
isResponseError
|
|
13
|
-
} from "../../chunk-TGTPXCLF.mjs";
|
|
11
|
+
createRequestId
|
|
12
|
+
} from "../../chunk-BUCULLYM.mjs";
|
|
14
13
|
|
|
15
14
|
// src/interceptors/fetch/index.ts
|
|
16
15
|
import { invariant } from "outvariant";
|
|
17
16
|
import { DeferredPromise } from "@open-draft/deferred-promise";
|
|
18
|
-
import { until } from "@open-draft/until";
|
|
19
17
|
|
|
20
18
|
// src/utils/canParseUrl.ts
|
|
21
19
|
function canParseUrl(url) {
|
|
@@ -42,131 +40,62 @@ var _FetchInterceptor = class extends Interceptor {
|
|
|
42
40
|
'Failed to patch the "fetch" module: already patched.'
|
|
43
41
|
);
|
|
44
42
|
globalThis.fetch = async (input, init) => {
|
|
45
|
-
var _a;
|
|
46
43
|
const requestId = createRequestId();
|
|
47
44
|
const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input;
|
|
48
45
|
const request = new Request(resolvedInput, init);
|
|
46
|
+
const responsePromise = new DeferredPromise();
|
|
47
|
+
const controller = new RequestController(request);
|
|
49
48
|
this.logger.info("[%s] %s", request.method, request.url);
|
|
50
|
-
|
|
49
|
+
this.logger.info("awaiting for the mocked response...");
|
|
51
50
|
this.logger.info(
|
|
52
|
-
'emitting the "request" event for %
|
|
51
|
+
'emitting the "request" event for %s listener(s)...',
|
|
53
52
|
this.emitter.listenerCount("request")
|
|
54
53
|
);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.logger.info("awaiting for the mocked response...");
|
|
64
|
-
const signal = interactiveRequest.signal;
|
|
65
|
-
const requestAborted = new DeferredPromise();
|
|
66
|
-
if (signal) {
|
|
67
|
-
signal.addEventListener(
|
|
68
|
-
"abort",
|
|
69
|
-
() => {
|
|
70
|
-
requestAborted.reject(signal.reason);
|
|
71
|
-
},
|
|
72
|
-
{ once: true }
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
const responsePromise = new DeferredPromise();
|
|
76
|
-
const respondWith = (response) => {
|
|
77
|
-
this.logger.info("responding with a mock response:", response);
|
|
78
|
-
if (this.emitter.listenerCount("response") > 0) {
|
|
79
|
-
this.logger.info('emitting the "response" event...');
|
|
80
|
-
const responseClone = response.clone();
|
|
81
|
-
this.emitter.emit("response", {
|
|
82
|
-
response: responseClone,
|
|
83
|
-
isMockedResponse: true,
|
|
84
|
-
request: interactiveRequest,
|
|
85
|
-
requestId
|
|
54
|
+
const isRequestHandled = await handleRequest({
|
|
55
|
+
request,
|
|
56
|
+
requestId,
|
|
57
|
+
emitter: this.emitter,
|
|
58
|
+
controller,
|
|
59
|
+
onResponse: async (response) => {
|
|
60
|
+
this.logger.info("received mocked response!", {
|
|
61
|
+
response
|
|
86
62
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
const resolverResult = await until(
|
|
100
|
-
async () => {
|
|
101
|
-
const listenersFinished = emitAsync(this.emitter, "request", {
|
|
102
|
-
request: interactiveRequest,
|
|
103
|
-
requestId
|
|
104
|
-
});
|
|
105
|
-
await Promise.race([
|
|
106
|
-
requestAborted,
|
|
107
|
-
// Put the listeners invocation Promise in the same race condition
|
|
108
|
-
// with the request abort Promise because otherwise awaiting the listeners
|
|
109
|
-
// would always yield some response (or undefined).
|
|
110
|
-
listenersFinished,
|
|
111
|
-
requestController.responsePromise
|
|
112
|
-
]);
|
|
113
|
-
this.logger.info("all request listeners have been resolved!");
|
|
114
|
-
const mockedResponse2 = await requestController.responsePromise;
|
|
115
|
-
this.logger.info("event.respondWith called with:", mockedResponse2);
|
|
116
|
-
return mockedResponse2;
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
if (requestAborted.state === "rejected") {
|
|
120
|
-
this.logger.info(
|
|
121
|
-
"request has been aborted:",
|
|
122
|
-
requestAborted.rejectionReason
|
|
123
|
-
);
|
|
124
|
-
responsePromise.reject(requestAborted.rejectionReason);
|
|
125
|
-
return responsePromise;
|
|
126
|
-
}
|
|
127
|
-
if (resolverResult.error) {
|
|
128
|
-
this.logger.info(
|
|
129
|
-
"request listerner threw an error:",
|
|
130
|
-
resolverResult.error
|
|
131
|
-
);
|
|
132
|
-
if (resolverResult.error instanceof Response) {
|
|
133
|
-
if (isResponseError(resolverResult.error)) {
|
|
134
|
-
errorWith(createNetworkError(resolverResult.error));
|
|
135
|
-
} else {
|
|
136
|
-
respondWith(resolverResult.error);
|
|
63
|
+
if (this.emitter.listenerCount("response") > 0) {
|
|
64
|
+
this.logger.info('emitting the "response" event...');
|
|
65
|
+
await emitAsync(this.emitter, "response", {
|
|
66
|
+
// Clone the mocked response for the "response" event listener.
|
|
67
|
+
// This way, the listener can read the response and not lock its body
|
|
68
|
+
// for the actual fetch consumer.
|
|
69
|
+
response: response.clone(),
|
|
70
|
+
isMockedResponse: true,
|
|
71
|
+
request,
|
|
72
|
+
requestId
|
|
73
|
+
});
|
|
137
74
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
request
|
|
143
|
-
requestId,
|
|
144
|
-
controller: {
|
|
145
|
-
respondWith,
|
|
146
|
-
errorWith
|
|
147
|
-
}
|
|
75
|
+
Object.defineProperty(response, "url", {
|
|
76
|
+
writable: false,
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: false,
|
|
79
|
+
value: request.url
|
|
148
80
|
});
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.logger.info("received mocked response:", mockedResponse);
|
|
159
|
-
if (isResponseError(mockedResponse)) {
|
|
160
|
-
this.logger.info(
|
|
161
|
-
"received a network error response, rejecting the request promise..."
|
|
162
|
-
);
|
|
163
|
-
errorWith(createNetworkError(mockedResponse));
|
|
164
|
-
} else {
|
|
165
|
-
respondWith(mockedResponse);
|
|
81
|
+
responsePromise.resolve(response);
|
|
82
|
+
},
|
|
83
|
+
onRequestError: (response) => {
|
|
84
|
+
this.logger.info("request has errored!", { response });
|
|
85
|
+
responsePromise.reject(createNetworkError(response));
|
|
86
|
+
},
|
|
87
|
+
onError: (error) => {
|
|
88
|
+
this.logger.info("request has been aborted!", { error });
|
|
89
|
+
responsePromise.reject(error);
|
|
166
90
|
}
|
|
91
|
+
});
|
|
92
|
+
if (isRequestHandled) {
|
|
93
|
+
this.logger.info("request has been handled, returning mock promise...");
|
|
167
94
|
return responsePromise;
|
|
168
95
|
}
|
|
169
|
-
this.logger.info(
|
|
96
|
+
this.logger.info(
|
|
97
|
+
"no mocked response received, performing request as-is..."
|
|
98
|
+
);
|
|
170
99
|
return pureFetch(request).then((response) => {
|
|
171
100
|
this.logger.info("original fetch performed", response);
|
|
172
101
|
if (this.emitter.listenerCount("response") > 0) {
|
|
@@ -175,7 +104,7 @@ var _FetchInterceptor = class extends Interceptor {
|
|
|
175
104
|
this.emitter.emit("response", {
|
|
176
105
|
response: responseClone,
|
|
177
106
|
isMockedResponse: false,
|
|
178
|
-
request
|
|
107
|
+
request,
|
|
179
108
|
requestId
|
|
180
109
|
});
|
|
181
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { toInteractiveRequest } from '../../utils/toInteractiveRequest'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport {\n createServerErrorResponse,\n isResponseError,\n} from '../../utils/responseUtils'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n\n this.logger.info('[%s] %s', request.method, request.url)\n\n const { interactiveRequest, requestController } =\n toInteractiveRequest(request)\n\n this.logger.info(\n 'emitting the \"request\" event for %d listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n this.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== requestId) {\n return\n }\n\n if (requestController.responsePromise.state === 'pending') {\n requestController.responsePromise.resolve(undefined)\n }\n })\n\n this.logger.info('awaiting for the mocked response...')\n\n const signal = interactiveRequest.signal\n const requestAborted = new DeferredPromise()\n\n // Signal isn't always defined in react-native.\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n requestAborted.reject(signal.reason)\n },\n { once: true }\n )\n }\n\n const responsePromise = new DeferredPromise<Response>()\n\n const respondWith = (response: Response): void => {\n this.logger.info('responding with a mock response:', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: true,\n request: interactiveRequest,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n }\n\n const errorWith = (reason: unknown): void => {\n responsePromise.reject(reason)\n }\n\n const resolverResult = await until<unknown, Response | undefined>(\n async () => {\n const listenersFinished = emitAsync(this.emitter, 'request', {\n request: interactiveRequest,\n requestId,\n })\n\n await Promise.race([\n requestAborted,\n // Put the listeners invocation Promise in the same race condition\n // with the request abort Promise because otherwise awaiting the listeners\n // would always yield some response (or undefined).\n listenersFinished,\n requestController.responsePromise,\n ])\n\n this.logger.info('all request listeners have been resolved!')\n\n const mockedResponse = await requestController.responsePromise\n this.logger.info('event.respondWith called with:', mockedResponse)\n\n return mockedResponse\n }\n )\n\n if (requestAborted.state === 'rejected') {\n this.logger.info(\n 'request has been aborted:',\n requestAborted.rejectionReason\n )\n\n responsePromise.reject(requestAborted.rejectionReason)\n return responsePromise\n }\n\n if (resolverResult.error) {\n this.logger.info(\n 'request listerner threw an error:',\n resolverResult.error\n )\n\n // Treat thrown Responses as mocked responses.\n if (resolverResult.error instanceof Response) {\n // Treat thrown Response.error() as a request error.\n if (isResponseError(resolverResult.error)) {\n errorWith(createNetworkError(resolverResult.error))\n } else {\n // Treat the rest of thrown Responses as mocked responses.\n respondWith(resolverResult.error)\n }\n }\n\n // Emit the \"unhandledException\" interceptor event so the client\n // can opt-out from exceptions translating to 500 error responses.\n\n if (this.emitter.listenerCount('unhandledException') > 0) {\n await emitAsync(this.emitter, 'unhandledException', {\n error: resolverResult.error,\n request,\n requestId,\n controller: {\n respondWith,\n errorWith,\n },\n })\n\n if (responsePromise.state !== 'pending') {\n return responsePromise\n }\n }\n\n // Unhandled exceptions in the request listeners are\n // synonymous to unhandled exceptions on the server.\n // Those are represented as 500 error responses.\n respondWith(createServerErrorResponse(resolverResult.error))\n return responsePromise\n }\n\n const mockedResponse = resolverResult.data\n\n if (mockedResponse && !request.signal?.aborted) {\n this.logger.info('received mocked response:', mockedResponse)\n\n // Reject the request Promise on mocked \"Response.error\" responses.\n if (isResponseError(mockedResponse)) {\n this.logger.info(\n 'received a network error response, rejecting the request promise...'\n )\n\n /**\n * Set the cause of the request promise rejection to the\n * network error Response instance. This differs from Undici.\n * Undici will forward the \"response.error\" custom property\n * as the rejection reason but for \"Response.error()\" static method\n * \"response.error\" will equal to undefined, making \"cause\" an empty Error.\n * @see https://github.com/nodejs/undici/blob/83cb522ae0157a19d149d72c7d03d46e34510d0a/lib/fetch/response.js#L344\n */\n errorWith(createNetworkError(mockedResponse))\n } else {\n respondWith(mockedResponse)\n }\n\n return responsePromise\n }\n\n this.logger.info('no mocked response received!')\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request: interactiveRequest,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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","names":["mockedResponse"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/interceptors/fetch/index.ts","../../../../src/utils/canParseUrl.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\n\nexport class FetchInterceptor extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch !== 'undefined'\n )\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise<Response>()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (response) => {\n this.logger.info('received mocked response!', {\n response,\n })\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n // Set the \"response.url\" property to equal the intercepted request URL.\n Object.defineProperty(response, 'url', {\n writable: false,\n enumerable: true,\n configurable: false,\n value: request.url,\n })\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then((response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n this.emitter.emit('response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n\nfunction createNetworkError(cause: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientRequestInterceptor } from '../interceptors/ClientRequest/index.js';
|
|
2
2
|
import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest/index.js';
|
|
3
|
-
import '../Interceptor-
|
|
3
|
+
import '../Interceptor-a31b1217.js';
|
|
4
4
|
import '@open-draft/deferred-promise';
|
|
5
5
|
import '@open-draft/logger';
|
|
6
6
|
import 'strict-event-emitter';
|
package/lib/node/presets/node.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunk2MWIWEWVjs = require('../chunk-2MWIWEWV.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkP6QG76R3js = require('../chunk-P6QG76R3.js');
|
|
7
7
|
require('../chunk-LK6DILFK.js');
|
|
8
|
-
require('../chunk-
|
|
9
|
-
require('../chunk-
|
|
10
|
-
require('../chunk-
|
|
8
|
+
require('../chunk-IDEEMJ3F.js');
|
|
9
|
+
require('../chunk-5WWNCLB3.js');
|
|
10
|
+
require('../chunk-YGM3BCJU.js');
|
|
11
11
|
|
|
12
12
|
// src/presets/node.ts
|
|
13
13
|
var node_default = [
|
|
14
|
-
new (0,
|
|
15
|
-
new (0,
|
|
14
|
+
new (0, _chunk2MWIWEWVjs.ClientRequestInterceptor)(),
|
|
15
|
+
new (0, _chunkP6QG76R3js.XMLHttpRequestInterceptor)()
|
|
16
16
|
];
|
|
17
17
|
|
|
18
18
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClientRequestInterceptor
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-CU3YXMM4.mjs";
|
|
4
4
|
import {
|
|
5
5
|
XMLHttpRequestInterceptor
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-TOV4TYIX.mjs";
|
|
7
7
|
import "../chunk-6HYIRFX2.mjs";
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-BZ3Y7YV5.mjs";
|
|
9
|
+
import "../chunk-KY3RJ2M3.mjs";
|
|
10
|
+
import "../chunk-BUCULLYM.mjs";
|
|
11
11
|
|
|
12
12
|
// src/presets/node.ts
|
|
13
13
|
var node_default = [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mswjs/interceptors",
|
|
3
3
|
"description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.33.0",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
"@open-draft/logger": "^0.3.0",
|
|
162
162
|
"@open-draft/until": "^2.0.0",
|
|
163
163
|
"is-node-process": "^1.2.0",
|
|
164
|
-
"outvariant": "^1.
|
|
164
|
+
"outvariant": "^1.4.3",
|
|
165
165
|
"strict-event-emitter": "^0.5.1"
|
|
166
166
|
},
|
|
167
167
|
"resolutions": {
|