importmap_mocha-rails 0.3.2 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/importmap_mocha/engine.rb +9 -0
- data/lib/importmap_mocha/version.rb +1 -1
- data/vendor/javascripts/@mswjs--interceptors--presets--browser.js +305 -173
- data/vendor/javascripts/@mswjs--interceptors.js +8 -0
- data/vendor/javascripts/chai.js +120 -132
- data/vendor/javascripts/mocha.js +402 -310
- data/vendor/stylesheets/mocha.css +54 -17
- metadata +2 -3
- data/vendor/javascripts/mocha.js.map +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55c9689c64ecb2902d9fcb77c63837596a8a7f6a3409d33b08384e1adb92db5d
|
4
|
+
data.tar.gz: e7f7fbe95e2e778add22a79931a7b0b8ced8fe2ea5a1263a52b476826918cc85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b57ba9684a4778aa2304d4daaca9b8dcdc9685b7992ba3bfece3bf120736d05a9e3dd96d0153eed4e3d23e2e729ffde4c7530b7acd0f9a855a997640e6294855
|
7
|
+
data.tar.gz: 73568ec4bf12eba6c7fe126babd98cf443c4cd4a0c8c24629080d434888d5a8dc4d3c128eecec2d671c6c3556f629ca71fa1584c2c58d5c8f1376307d1d8af41
|
data/README.md
CHANGED
@@ -30,6 +30,15 @@ module ImportmapMocha
|
|
30
30
|
app.config.importmap.paths << Engine.root.join('config/importmap.rb') if Rails.application.respond_to?(:importmap)
|
31
31
|
end
|
32
32
|
|
33
|
+
initializer "importmap_mocha.cache_sweeper", before: "importmap.cache_sweeper" do |app|
|
34
|
+
if app.config.importmap.sweep_cache && !app.config.cache_classes
|
35
|
+
app.config.importmap.cache_sweepers << Engine.root.join('app/assets/javascripts')
|
36
|
+
app.config.importmap.cache_sweepers << Engine.root.join('vendor/javascripts')
|
37
|
+
app.config.importmap.cache_sweepers += Rails.application.config.importmap_mocha_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
33
42
|
initializer 'importmap_mocha.routes' do
|
34
43
|
Rails.application.routes.prepend do
|
35
44
|
scope module: 'importmap_mocha' do
|
@@ -1,7 +1,6 @@
|
|
1
1
|
// src/interceptors/fetch/index.ts
|
2
2
|
import { invariant as invariant2 } from "outvariant";
|
3
|
-
import { DeferredPromise as
|
4
|
-
import { until } from "@open-draft/until";
|
3
|
+
import { DeferredPromise as DeferredPromise3 } from "@open-draft/deferred-promise";
|
5
4
|
|
6
5
|
// src/glossary.ts
|
7
6
|
var IS_PATCHED_MODULE = Symbol("isPatchedModule");
|
@@ -9,6 +8,7 @@ var IS_PATCHED_MODULE = Symbol("isPatchedModule");
|
|
9
8
|
// src/Interceptor.ts
|
10
9
|
import { Logger } from "@open-draft/logger";
|
11
10
|
import { Emitter } from "strict-event-emitter";
|
11
|
+
var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id";
|
12
12
|
function getGlobalSymbol(symbol) {
|
13
13
|
return (
|
14
14
|
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587
|
@@ -152,47 +152,65 @@ var Interceptor = class {
|
|
152
152
|
}
|
153
153
|
};
|
154
154
|
|
155
|
-
// src/
|
156
|
-
function uuidv4() {
|
157
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
158
|
-
const r = Math.random() * 16 | 0;
|
159
|
-
const v = c == "x" ? r : r & 3 | 8;
|
160
|
-
return v.toString(16);
|
161
|
-
});
|
162
|
-
}
|
163
|
-
|
164
|
-
// src/utils/RequestController.ts
|
155
|
+
// src/RequestController.ts
|
165
156
|
import { invariant } from "outvariant";
|
166
157
|
import { DeferredPromise } from "@open-draft/deferred-promise";
|
158
|
+
|
159
|
+
// src/InterceptorError.ts
|
160
|
+
var InterceptorError = class extends Error {
|
161
|
+
constructor(message) {
|
162
|
+
super(message);
|
163
|
+
this.name = "InterceptorError";
|
164
|
+
Object.setPrototypeOf(this, InterceptorError.prototype);
|
165
|
+
}
|
166
|
+
};
|
167
|
+
|
168
|
+
// src/RequestController.ts
|
169
|
+
var kRequestHandled = Symbol("kRequestHandled");
|
170
|
+
var kResponsePromise = Symbol("kResponsePromise");
|
167
171
|
var RequestController = class {
|
168
172
|
constructor(request) {
|
169
173
|
this.request = request;
|
170
|
-
this
|
174
|
+
this[kRequestHandled] = false;
|
175
|
+
this[kResponsePromise] = new DeferredPromise();
|
171
176
|
}
|
177
|
+
/**
|
178
|
+
* Respond to this request with the given `Response` instance.
|
179
|
+
* @example
|
180
|
+
* controller.respondWith(new Response())
|
181
|
+
* controller.respondWith(Response.json({ id }))
|
182
|
+
* controller.respondWith(Response.error())
|
183
|
+
*/
|
172
184
|
respondWith(response) {
|
173
|
-
invariant(
|
174
|
-
|
175
|
-
|
185
|
+
invariant.as(
|
186
|
+
InterceptorError,
|
187
|
+
!this[kRequestHandled],
|
188
|
+
'Failed to respond to the "%s %s" request: the "request" event has already been handled.',
|
189
|
+
this.request.method,
|
190
|
+
this.request.url
|
191
|
+
);
|
192
|
+
this[kRequestHandled] = true;
|
193
|
+
this[kResponsePromise].resolve(response);
|
194
|
+
}
|
195
|
+
/**
|
196
|
+
* Error this request with the given error.
|
197
|
+
* @example
|
198
|
+
* controller.errorWith()
|
199
|
+
* controller.errorWith(new Error('Oops!'))
|
200
|
+
*/
|
201
|
+
errorWith(error) {
|
202
|
+
invariant.as(
|
203
|
+
InterceptorError,
|
204
|
+
!this[kRequestHandled],
|
205
|
+
'Failed to error the "%s %s" request: the "request" event has already been handled.',
|
176
206
|
this.request.method,
|
177
207
|
this.request.url
|
178
208
|
);
|
179
|
-
this
|
209
|
+
this[kRequestHandled] = true;
|
210
|
+
this[kResponsePromise].resolve(error);
|
180
211
|
}
|
181
212
|
};
|
182
|
-
|
183
|
-
// src/utils/toInteractiveRequest.ts
|
184
|
-
function toInteractiveRequest(request) {
|
185
|
-
const requestController = new RequestController(request);
|
186
|
-
Reflect.set(
|
187
|
-
request,
|
188
|
-
"respondWith",
|
189
|
-
requestController.respondWith.bind(requestController)
|
190
|
-
);
|
191
|
-
return {
|
192
|
-
interactiveRequest: request,
|
193
|
-
requestController
|
194
|
-
};
|
195
|
-
}
|
213
|
+
kResponsePromise, kRequestHandled;
|
196
214
|
|
197
215
|
// src/utils/emitAsync.ts
|
198
216
|
async function emitAsync(emitter, eventName, ...data) {
|
@@ -205,6 +223,10 @@ async function emitAsync(emitter, eventName, ...data) {
|
|
205
223
|
}
|
206
224
|
}
|
207
225
|
|
226
|
+
// src/utils/handleRequest.ts
|
227
|
+
import { DeferredPromise as DeferredPromise2 } from "@open-draft/deferred-promise";
|
228
|
+
import { until } from "@open-draft/until";
|
229
|
+
|
208
230
|
// src/utils/isPropertyAccessible.ts
|
209
231
|
function isPropertyAccessible(obj, key) {
|
210
232
|
try {
|
@@ -215,6 +237,164 @@ function isPropertyAccessible(obj, key) {
|
|
215
237
|
}
|
216
238
|
}
|
217
239
|
|
240
|
+
// src/utils/responseUtils.ts
|
241
|
+
var RESPONSE_STATUS_CODES_WITHOUT_BODY = /* @__PURE__ */ new Set([
|
242
|
+
101,
|
243
|
+
103,
|
244
|
+
204,
|
245
|
+
205,
|
246
|
+
304
|
247
|
+
]);
|
248
|
+
function isResponseWithoutBody(status) {
|
249
|
+
return RESPONSE_STATUS_CODES_WITHOUT_BODY.has(status);
|
250
|
+
}
|
251
|
+
function createServerErrorResponse(body) {
|
252
|
+
return new Response(
|
253
|
+
JSON.stringify(
|
254
|
+
body instanceof Error ? {
|
255
|
+
name: body.name,
|
256
|
+
message: body.message,
|
257
|
+
stack: body.stack
|
258
|
+
} : body
|
259
|
+
),
|
260
|
+
{
|
261
|
+
status: 500,
|
262
|
+
statusText: "Unhandled Exception",
|
263
|
+
headers: {
|
264
|
+
"Content-Type": "application/json"
|
265
|
+
}
|
266
|
+
}
|
267
|
+
);
|
268
|
+
}
|
269
|
+
function isResponseError(response) {
|
270
|
+
return isPropertyAccessible(response, "type") && response.type === "error";
|
271
|
+
}
|
272
|
+
|
273
|
+
// src/utils/isNodeLikeError.ts
|
274
|
+
function isNodeLikeError(error) {
|
275
|
+
if (error == null) {
|
276
|
+
return false;
|
277
|
+
}
|
278
|
+
if (!(error instanceof Error)) {
|
279
|
+
return false;
|
280
|
+
}
|
281
|
+
return "code" in error && "errno" in error;
|
282
|
+
}
|
283
|
+
|
284
|
+
// src/utils/handleRequest.ts
|
285
|
+
async function handleRequest(options) {
|
286
|
+
const handleResponse = (response) => {
|
287
|
+
if (response instanceof Error) {
|
288
|
+
options.onError(response);
|
289
|
+
} else if (isResponseError(response)) {
|
290
|
+
options.onRequestError(response);
|
291
|
+
} else {
|
292
|
+
options.onResponse(response);
|
293
|
+
}
|
294
|
+
return true;
|
295
|
+
};
|
296
|
+
const handleResponseError = (error) => {
|
297
|
+
if (error instanceof InterceptorError) {
|
298
|
+
throw result.error;
|
299
|
+
}
|
300
|
+
if (isNodeLikeError(error)) {
|
301
|
+
options.onError(error);
|
302
|
+
return true;
|
303
|
+
}
|
304
|
+
if (error instanceof Response) {
|
305
|
+
return handleResponse(error);
|
306
|
+
}
|
307
|
+
return false;
|
308
|
+
};
|
309
|
+
options.emitter.once("request", ({ requestId: pendingRequestId }) => {
|
310
|
+
if (pendingRequestId !== options.requestId) {
|
311
|
+
return;
|
312
|
+
}
|
313
|
+
if (options.controller[kResponsePromise].state === "pending") {
|
314
|
+
options.controller[kResponsePromise].resolve(void 0);
|
315
|
+
}
|
316
|
+
});
|
317
|
+
const requestAbortPromise = new DeferredPromise2();
|
318
|
+
if (options.request.signal) {
|
319
|
+
options.request.signal.addEventListener(
|
320
|
+
"abort",
|
321
|
+
() => {
|
322
|
+
requestAbortPromise.reject(options.request.signal.reason);
|
323
|
+
},
|
324
|
+
{ once: true }
|
325
|
+
);
|
326
|
+
}
|
327
|
+
const result = await until(async () => {
|
328
|
+
const requestListtenersPromise = emitAsync(options.emitter, "request", {
|
329
|
+
requestId: options.requestId,
|
330
|
+
request: options.request,
|
331
|
+
controller: options.controller
|
332
|
+
});
|
333
|
+
await Promise.race([
|
334
|
+
// Short-circuit the request handling promise if the request gets aborted.
|
335
|
+
requestAbortPromise,
|
336
|
+
requestListtenersPromise,
|
337
|
+
options.controller[kResponsePromise]
|
338
|
+
]);
|
339
|
+
const mockedResponse = await options.controller[kResponsePromise];
|
340
|
+
return mockedResponse;
|
341
|
+
});
|
342
|
+
if (requestAbortPromise.state === "rejected") {
|
343
|
+
options.onError(requestAbortPromise.rejectionReason);
|
344
|
+
return true;
|
345
|
+
}
|
346
|
+
if (result.error) {
|
347
|
+
if (handleResponseError(result.error)) {
|
348
|
+
return true;
|
349
|
+
}
|
350
|
+
if (options.emitter.listenerCount("unhandledException") > 0) {
|
351
|
+
const unhandledExceptionController = new RequestController(
|
352
|
+
options.request
|
353
|
+
);
|
354
|
+
await emitAsync(options.emitter, "unhandledException", {
|
355
|
+
error: result.error,
|
356
|
+
request: options.request,
|
357
|
+
requestId: options.requestId,
|
358
|
+
controller: unhandledExceptionController
|
359
|
+
}).then(() => {
|
360
|
+
if (unhandledExceptionController[kResponsePromise].state === "pending") {
|
361
|
+
unhandledExceptionController[kResponsePromise].resolve(void 0);
|
362
|
+
}
|
363
|
+
});
|
364
|
+
const nextResult = await until(
|
365
|
+
() => unhandledExceptionController[kResponsePromise]
|
366
|
+
);
|
367
|
+
if (nextResult.error) {
|
368
|
+
return handleResponseError(nextResult.error);
|
369
|
+
}
|
370
|
+
if (nextResult.data) {
|
371
|
+
return handleResponse(nextResult.data);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
options.onResponse(createServerErrorResponse(result.error));
|
375
|
+
return true;
|
376
|
+
}
|
377
|
+
if (result.data) {
|
378
|
+
return handleResponse(result.data);
|
379
|
+
}
|
380
|
+
return false;
|
381
|
+
}
|
382
|
+
|
383
|
+
// src/utils/canParseUrl.ts
|
384
|
+
function canParseUrl(url) {
|
385
|
+
try {
|
386
|
+
new URL(url);
|
387
|
+
return true;
|
388
|
+
} catch (_error) {
|
389
|
+
return false;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
// src/createRequestId.ts
|
394
|
+
function createRequestId() {
|
395
|
+
return Math.random().toString(16).slice(2);
|
396
|
+
}
|
397
|
+
|
218
398
|
// src/interceptors/fetch/index.ts
|
219
399
|
var _FetchInterceptor = class extends Interceptor {
|
220
400
|
constructor() {
|
@@ -223,99 +403,81 @@ var _FetchInterceptor = class extends Interceptor {
|
|
223
403
|
checkEnvironment() {
|
224
404
|
return typeof globalThis !== "undefined" && typeof globalThis.fetch !== "undefined";
|
225
405
|
}
|
226
|
-
setup() {
|
406
|
+
async setup() {
|
227
407
|
const pureFetch = globalThis.fetch;
|
228
408
|
invariant2(
|
229
409
|
!pureFetch[IS_PATCHED_MODULE],
|
230
410
|
'Failed to patch the "fetch" module: already patched.'
|
231
411
|
);
|
232
412
|
globalThis.fetch = async (input, init) => {
|
233
|
-
|
234
|
-
const
|
235
|
-
const request = new Request(
|
413
|
+
const requestId = createRequestId();
|
414
|
+
const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input;
|
415
|
+
const request = new Request(resolvedInput, init);
|
416
|
+
const responsePromise = new DeferredPromise3();
|
417
|
+
const controller = new RequestController(request);
|
236
418
|
this.logger.info("[%s] %s", request.method, request.url);
|
237
|
-
|
419
|
+
this.logger.info("awaiting for the mocked response...");
|
238
420
|
this.logger.info(
|
239
|
-
'emitting the "request" event for %
|
421
|
+
'emitting the "request" event for %s listener(s)...',
|
240
422
|
this.emitter.listenerCount("request")
|
241
423
|
);
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
424
|
+
const isRequestHandled = await handleRequest({
|
425
|
+
request,
|
426
|
+
requestId,
|
427
|
+
emitter: this.emitter,
|
428
|
+
controller,
|
429
|
+
onResponse: async (response) => {
|
430
|
+
this.logger.info("received mocked response!", {
|
431
|
+
response
|
432
|
+
});
|
433
|
+
if (this.emitter.listenerCount("response") > 0) {
|
434
|
+
this.logger.info('emitting the "response" event...');
|
435
|
+
await emitAsync(this.emitter, "response", {
|
436
|
+
// Clone the mocked response for the "response" event listener.
|
437
|
+
// This way, the listener can read the response and not lock its body
|
438
|
+
// for the actual fetch consumer.
|
439
|
+
response: response.clone(),
|
440
|
+
isMockedResponse: true,
|
441
|
+
request,
|
442
|
+
requestId
|
443
|
+
});
|
444
|
+
}
|
445
|
+
Object.defineProperty(response, "url", {
|
446
|
+
writable: false,
|
447
|
+
enumerable: true,
|
448
|
+
configurable: false,
|
449
|
+
value: request.url
|
450
|
+
});
|
451
|
+
responsePromise.resolve(response);
|
257
452
|
},
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
await Promise.race([
|
266
|
-
requestAborted,
|
267
|
-
// Put the listeners invocation Promise in the same race condition
|
268
|
-
// with the request abort Promise because otherwise awaiting the listeners
|
269
|
-
// would always yield some response (or undefined).
|
270
|
-
listenersFinished,
|
271
|
-
requestController.responsePromise
|
272
|
-
]);
|
273
|
-
this.logger.info("all request listeners have been resolved!");
|
274
|
-
const mockedResponse2 = await requestController.responsePromise;
|
275
|
-
this.logger.info("event.respondWith called with:", mockedResponse2);
|
276
|
-
return mockedResponse2;
|
277
|
-
});
|
278
|
-
if (requestAborted.state === "rejected") {
|
279
|
-
return Promise.reject(requestAborted.rejectionReason);
|
280
|
-
}
|
281
|
-
if (resolverResult.error) {
|
282
|
-
return Promise.reject(createNetworkError(resolverResult.error));
|
283
|
-
}
|
284
|
-
const mockedResponse = resolverResult.data;
|
285
|
-
if (mockedResponse && !((_a = request.signal) == null ? void 0 : _a.aborted)) {
|
286
|
-
this.logger.info("received mocked response:", mockedResponse);
|
287
|
-
if (isPropertyAccessible(mockedResponse, "type") && mockedResponse.type === "error") {
|
288
|
-
this.logger.info(
|
289
|
-
"received a network error response, rejecting the request promise..."
|
290
|
-
);
|
291
|
-
return Promise.reject(createNetworkError(mockedResponse));
|
453
|
+
onRequestError: (response) => {
|
454
|
+
this.logger.info("request has errored!", { response });
|
455
|
+
responsePromise.reject(createNetworkError(response));
|
456
|
+
},
|
457
|
+
onError: (error) => {
|
458
|
+
this.logger.info("request has been aborted!", { error });
|
459
|
+
responsePromise.reject(error);
|
292
460
|
}
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
request: interactiveRequest,
|
298
|
-
requestId
|
299
|
-
});
|
300
|
-
const response = new Response(mockedResponse.body, mockedResponse);
|
301
|
-
Object.defineProperty(response, "url", {
|
302
|
-
writable: false,
|
303
|
-
enumerable: true,
|
304
|
-
configurable: false,
|
305
|
-
value: request.url
|
306
|
-
});
|
307
|
-
return response;
|
461
|
+
});
|
462
|
+
if (isRequestHandled) {
|
463
|
+
this.logger.info("request has been handled, returning mock promise...");
|
464
|
+
return responsePromise;
|
308
465
|
}
|
309
|
-
this.logger.info(
|
466
|
+
this.logger.info(
|
467
|
+
"no mocked response received, performing request as-is..."
|
468
|
+
);
|
310
469
|
return pureFetch(request).then((response) => {
|
311
|
-
|
312
|
-
this.
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
470
|
+
this.logger.info("original fetch performed", response);
|
471
|
+
if (this.emitter.listenerCount("response") > 0) {
|
472
|
+
this.logger.info('emitting the "response" event...');
|
473
|
+
const responseClone = response.clone();
|
474
|
+
this.emitter.emit("response", {
|
475
|
+
response: responseClone,
|
476
|
+
isMockedResponse: false,
|
477
|
+
request,
|
478
|
+
requestId
|
479
|
+
});
|
480
|
+
}
|
319
481
|
return response;
|
320
482
|
});
|
321
483
|
};
|
@@ -347,9 +509,6 @@ function createNetworkError(cause) {
|
|
347
509
|
// src/interceptors/XMLHttpRequest/index.ts
|
348
510
|
import { invariant as invariant4 } from "outvariant";
|
349
511
|
|
350
|
-
// src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts
|
351
|
-
import { until as until2 } from "@open-draft/until";
|
352
|
-
|
353
512
|
// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts
|
354
513
|
import { invariant as invariant3 } from "outvariant";
|
355
514
|
import { isNodeProcess } from "is-node-process";
|
@@ -547,18 +706,6 @@ function parseJson(data) {
|
|
547
706
|
}
|
548
707
|
}
|
549
708
|
|
550
|
-
// src/utils/responseUtils.ts
|
551
|
-
var RESPONSE_STATUS_CODES_WITHOUT_BODY = /* @__PURE__ */ new Set([
|
552
|
-
101,
|
553
|
-
103,
|
554
|
-
204,
|
555
|
-
205,
|
556
|
-
304
|
557
|
-
]);
|
558
|
-
function isResponseWithoutBody(status) {
|
559
|
-
return RESPONSE_STATUS_CODES_WITHOUT_BODY.has(status);
|
560
|
-
}
|
561
|
-
|
562
709
|
// src/interceptors/XMLHttpRequest/utils/createResponse.ts
|
563
710
|
function createResponse(request, body) {
|
564
711
|
const responseBodyOrNull = isResponseWithoutBody(request.status) ? null : body;
|
@@ -594,7 +741,7 @@ var XMLHttpRequestController = class {
|
|
594
741
|
this.method = "GET";
|
595
742
|
this.url = null;
|
596
743
|
this.events = /* @__PURE__ */ new Map();
|
597
|
-
this.requestId =
|
744
|
+
this.requestId = createRequestId();
|
598
745
|
this.requestHeaders = new Headers();
|
599
746
|
this.responseBuffer = new Uint8Array();
|
600
747
|
this.request = createProxy(initialRequest, {
|
@@ -676,7 +823,10 @@ var XMLHttpRequestController = class {
|
|
676
823
|
this.request.readyState
|
677
824
|
);
|
678
825
|
if (IS_NODE) {
|
679
|
-
this.request.setRequestHeader(
|
826
|
+
this.request.setRequestHeader(
|
827
|
+
INTERNAL_REQUEST_ID_HEADER_NAME,
|
828
|
+
this.requestId
|
829
|
+
);
|
680
830
|
}
|
681
831
|
return invoke();
|
682
832
|
}
|
@@ -1001,7 +1151,11 @@ function createXMLHttpRequestProxy({
|
|
1001
1151
|
const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {
|
1002
1152
|
construct(target, args, newTarget) {
|
1003
1153
|
logger.info("constructed new XMLHttpRequest");
|
1004
|
-
const originalRequest = Reflect.construct(
|
1154
|
+
const originalRequest = Reflect.construct(
|
1155
|
+
target,
|
1156
|
+
args,
|
1157
|
+
newTarget
|
1158
|
+
);
|
1005
1159
|
const prototypeDescriptors = Object.getOwnPropertyDescriptors(
|
1006
1160
|
target.prototype
|
1007
1161
|
);
|
@@ -1017,57 +1171,35 @@ function createXMLHttpRequestProxy({
|
|
1017
1171
|
logger
|
1018
1172
|
);
|
1019
1173
|
xhrRequestController.onRequest = async function({ request, requestId }) {
|
1020
|
-
const
|
1174
|
+
const controller = new RequestController(request);
|
1021
1175
|
this.logger.info("awaiting mocked response...");
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1176
|
+
this.logger.info(
|
1177
|
+
'emitting the "request" event for %s listener(s)...',
|
1178
|
+
emitter.listenerCount("request")
|
1179
|
+
);
|
1180
|
+
const isRequestHandled = await handleRequest({
|
1181
|
+
request,
|
1182
|
+
requestId,
|
1183
|
+
controller,
|
1184
|
+
emitter,
|
1185
|
+
onResponse: (response) => {
|
1186
|
+
this.respondWith(response);
|
1187
|
+
},
|
1188
|
+
onRequestError: () => {
|
1189
|
+
this.errorWith(new TypeError("Network error"));
|
1190
|
+
},
|
1191
|
+
onError: (error) => {
|
1192
|
+
this.logger.info("request errored!", { error });
|
1193
|
+
if (error instanceof Error) {
|
1194
|
+
this.errorWith(error);
|
1195
|
+
}
|
1028
1196
|
}
|
1029
1197
|
});
|
1030
|
-
|
1198
|
+
if (!isRequestHandled) {
|
1031
1199
|
this.logger.info(
|
1032
|
-
|
1033
|
-
emitter.listenerCount("request")
|
1200
|
+
"no mocked response received, performing request as-is..."
|
1034
1201
|
);
|
1035
|
-
await emitAsync(emitter, "request", {
|
1036
|
-
request: interactiveRequest,
|
1037
|
-
requestId
|
1038
|
-
});
|
1039
|
-
this.logger.info('all "request" listeners settled!');
|
1040
|
-
const mockedResponse2 = await requestController.responsePromise;
|
1041
|
-
this.logger.info("event.respondWith called with:", mockedResponse2);
|
1042
|
-
return mockedResponse2;
|
1043
|
-
});
|
1044
|
-
if (resolverResult.error) {
|
1045
|
-
this.logger.info(
|
1046
|
-
"request listener threw an exception, aborting request...",
|
1047
|
-
resolverResult.error
|
1048
|
-
);
|
1049
|
-
xhrRequestController.errorWith(resolverResult.error);
|
1050
|
-
return;
|
1051
1202
|
}
|
1052
|
-
const mockedResponse = resolverResult.data;
|
1053
|
-
if (typeof mockedResponse !== "undefined") {
|
1054
|
-
this.logger.info(
|
1055
|
-
"received mocked response: %d %s",
|
1056
|
-
mockedResponse.status,
|
1057
|
-
mockedResponse.statusText
|
1058
|
-
);
|
1059
|
-
if (mockedResponse.type === "error") {
|
1060
|
-
this.logger.info(
|
1061
|
-
"received a network error response, rejecting the request promise..."
|
1062
|
-
);
|
1063
|
-
xhrRequestController.errorWith(new TypeError("Network error"));
|
1064
|
-
return;
|
1065
|
-
}
|
1066
|
-
return xhrRequestController.respondWith(mockedResponse);
|
1067
|
-
}
|
1068
|
-
this.logger.info(
|
1069
|
-
"no mocked response received, performing request as-is..."
|
1070
|
-
);
|
1071
1203
|
};
|
1072
1204
|
xhrRequestController.onResponse = async function({
|
1073
1205
|
response,
|
@@ -4,6 +4,7 @@ var IS_PATCHED_MODULE = Symbol("isPatchedModule");
|
|
4
4
|
// src/Interceptor.ts
|
5
5
|
import { Logger } from "@open-draft/logger";
|
6
6
|
import { Emitter } from "strict-event-emitter";
|
7
|
+
var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id";
|
7
8
|
function getGlobalSymbol(symbol) {
|
8
9
|
return (
|
9
10
|
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587
|
@@ -198,6 +199,11 @@ var BatchInterceptor = class extends Interceptor {
|
|
198
199
|
}
|
199
200
|
};
|
200
201
|
|
202
|
+
// src/createRequestId.ts
|
203
|
+
function createRequestId() {
|
204
|
+
return Math.random().toString(16).slice(2);
|
205
|
+
}
|
206
|
+
|
201
207
|
// src/utils/getCleanUrl.ts
|
202
208
|
function getCleanUrl(url, isAbsolute = true) {
|
203
209
|
return [isAbsolute && url.origin, url.pathname].filter(Boolean).join("");
|
@@ -226,9 +232,11 @@ function isResponseWithoutBody(status) {
|
|
226
232
|
}
|
227
233
|
export {
|
228
234
|
BatchInterceptor,
|
235
|
+
INTERNAL_REQUEST_ID_HEADER_NAME,
|
229
236
|
IS_PATCHED_MODULE,
|
230
237
|
Interceptor,
|
231
238
|
InterceptorReadyState,
|
239
|
+
createRequestId,
|
232
240
|
decodeBuffer,
|
233
241
|
deleteGlobalSymbol,
|
234
242
|
encodeBuffer,
|