@mswjs/interceptors 0.24.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -202,8 +202,10 @@ function parseJson(data) {
202
202
  }
203
203
 
204
204
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
205
+ var statusCodesWithoutBody = [204, 205, 304];
205
206
  function createResponse(request, body) {
206
- return new Response(body, {
207
+ const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
208
+ return new Response(responseBodyOrNull, {
207
209
  status: request.status,
208
210
  statusText: request.statusText,
209
211
  headers: createHeadersFromXMLHttpReqestHeaders(
@@ -8,6 +8,7 @@ import {
8
8
  } from "./chunk-GXJLJMOT.mjs";
9
9
 
10
10
  // src/interceptors/fetch/index.ts
11
+ import { DeferredPromise } from "@open-draft/deferred-promise";
11
12
  import { invariant } from "outvariant";
12
13
  import { until } from "@open-draft/until";
13
14
  var _FetchInterceptor = class extends Interceptor {
@@ -38,18 +39,31 @@ var _FetchInterceptor = class extends Interceptor {
38
39
  requestId
39
40
  });
40
41
  this.logger.info("awaiting for the mocked response...");
42
+ const signal = interactiveRequest.signal;
43
+ const requestAborted = new DeferredPromise();
44
+ signal.addEventListener(
45
+ "abort",
46
+ () => {
47
+ requestAborted.reject(signal.reason);
48
+ },
49
+ { once: true }
50
+ );
41
51
  const resolverResult = await until(async () => {
42
- await this.emitter.untilIdle(
52
+ const allListenersResolved = this.emitter.untilIdle(
43
53
  "request",
44
54
  ({ args: [{ requestId: pendingRequestId }] }) => {
45
55
  return pendingRequestId === requestId;
46
56
  }
47
57
  );
58
+ await Promise.race([requestAborted, allListenersResolved]);
48
59
  this.logger.info("all request listeners have been resolved!");
49
60
  const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
50
61
  this.logger.info("event.respondWith called with:", mockedResponse2);
51
62
  return mockedResponse2;
52
63
  });
64
+ if (requestAborted.state === "rejected") {
65
+ return Promise.reject(requestAborted.rejectionReason);
66
+ }
53
67
  if (resolverResult.error) {
54
68
  const error = Object.assign(new TypeError("Failed to fetch"), {
55
69
  cause: resolverResult.error
@@ -8,6 +8,7 @@ var _chunkPCFJD76Xjs = require('./chunk-PCFJD76X.js');
8
8
  var _chunk4CFMDU7Zjs = require('./chunk-4CFMDU7Z.js');
9
9
 
10
10
  // src/interceptors/fetch/index.ts
11
+ var _deferredpromise = require('@open-draft/deferred-promise');
11
12
  var _outvariant = require('outvariant');
12
13
  var _until = require('@open-draft/until');
13
14
  var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
@@ -38,18 +39,31 @@ var _FetchInterceptor = class extends _chunk4CFMDU7Zjs.Interceptor {
38
39
  requestId
39
40
  });
40
41
  this.logger.info("awaiting for the mocked response...");
42
+ const signal = interactiveRequest.signal;
43
+ const requestAborted = new (0, _deferredpromise.DeferredPromise)();
44
+ signal.addEventListener(
45
+ "abort",
46
+ () => {
47
+ requestAborted.reject(signal.reason);
48
+ },
49
+ { once: true }
50
+ );
41
51
  const resolverResult = await _until.until.call(void 0, async () => {
42
- await this.emitter.untilIdle(
52
+ const allListenersResolved = this.emitter.untilIdle(
43
53
  "request",
44
54
  ({ args: [{ requestId: pendingRequestId }] }) => {
45
55
  return pendingRequestId === requestId;
46
56
  }
47
57
  );
58
+ await Promise.race([requestAborted, allListenersResolved]);
48
59
  this.logger.info("all request listeners have been resolved!");
49
60
  const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
50
61
  this.logger.info("event.respondWith called with:", mockedResponse2);
51
62
  return mockedResponse2;
52
63
  });
64
+ if (requestAborted.state === "rejected") {
65
+ return Promise.reject(requestAborted.rejectionReason);
66
+ }
53
67
  if (resolverResult.error) {
54
68
  const error = Object.assign(new TypeError("Failed to fetch"), {
55
69
  cause: resolverResult.error
@@ -202,8 +202,10 @@ function parseJson(data) {
202
202
  }
203
203
 
204
204
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
205
+ var statusCodesWithoutBody = [204, 205, 304];
205
206
  function createResponse(request, body) {
206
- return new Response(body, {
207
+ const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
208
+ return new Response(responseBodyOrNull, {
207
209
  status: request.status,
208
210
  statusText: request.statusText,
209
211
  headers: createHeadersFromXMLHttpReqestHeaders(
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkUGP4JOAMjs = require('../../chunk-UGP4JOAM.js');
3
+ var _chunkY4XXQXAWjs = require('../../chunk-Y4XXQXAW.js');
4
4
  require('../../chunk-3LFH2WCF.js');
5
5
  require('../../chunk-PCFJD76X.js');
6
6
  require('../../chunk-4CFMDU7Z.js');
7
7
 
8
8
 
9
- exports.XMLHttpRequestInterceptor = _chunkUGP4JOAMjs.XMLHttpRequestInterceptor;
9
+ exports.XMLHttpRequestInterceptor = _chunkY4XXQXAWjs.XMLHttpRequestInterceptor;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-B74BGPYH.mjs";
3
+ } from "../../chunk-BRIUGDYQ.mjs";
4
4
  import "../../chunk-7II4SWKS.mjs";
5
5
  import "../../chunk-RT3ATOJH.mjs";
6
6
  import "../../chunk-GXJLJMOT.mjs";
@@ -1,8 +1,8 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunk2TENISKMjs = require('../../chunk-2TENISKM.js');
3
+ var _chunkXAQQ5IUCjs = require('../../chunk-XAQQ5IUC.js');
4
4
  require('../../chunk-PCFJD76X.js');
5
5
  require('../../chunk-4CFMDU7Z.js');
6
6
 
7
7
 
8
- exports.FetchInterceptor = _chunk2TENISKMjs.FetchInterceptor;
8
+ exports.FetchInterceptor = _chunkXAQQ5IUCjs.FetchInterceptor;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  FetchInterceptor
3
- } from "../../chunk-LHYX2GOM.mjs";
3
+ } from "../../chunk-KSCN3JS4.mjs";
4
4
  import "../../chunk-RT3ATOJH.mjs";
5
5
  import "../../chunk-GXJLJMOT.mjs";
6
6
  export {
@@ -1,17 +1,17 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkUGP4JOAMjs = require('../chunk-UGP4JOAM.js');
3
+ var _chunkY4XXQXAWjs = require('../chunk-Y4XXQXAW.js');
4
4
  require('../chunk-3LFH2WCF.js');
5
5
 
6
6
 
7
- var _chunk2TENISKMjs = require('../chunk-2TENISKM.js');
7
+ var _chunkXAQQ5IUCjs = require('../chunk-XAQQ5IUC.js');
8
8
  require('../chunk-PCFJD76X.js');
9
9
  require('../chunk-4CFMDU7Z.js');
10
10
 
11
11
  // src/presets/browser.ts
12
12
  var browser_default = [
13
- new (0, _chunk2TENISKMjs.FetchInterceptor)(),
14
- new (0, _chunkUGP4JOAMjs.XMLHttpRequestInterceptor)()
13
+ new (0, _chunkXAQQ5IUCjs.FetchInterceptor)(),
14
+ new (0, _chunkY4XXQXAWjs.XMLHttpRequestInterceptor)()
15
15
  ];
16
16
 
17
17
 
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../chunk-B74BGPYH.mjs";
3
+ } from "../chunk-BRIUGDYQ.mjs";
4
4
  import "../chunk-7II4SWKS.mjs";
5
5
  import {
6
6
  FetchInterceptor
7
- } from "../chunk-LHYX2GOM.mjs";
7
+ } from "../chunk-KSCN3JS4.mjs";
8
8
  import "../chunk-RT3ATOJH.mjs";
9
9
  import "../chunk-GXJLJMOT.mjs";
10
10
 
@@ -6,7 +6,7 @@ var _chunkMVPEJK4Vjs = require('./chunk-MVPEJK4V.js');
6
6
  var _chunkOOSIWXHXjs = require('./chunk-OOSIWXHX.js');
7
7
 
8
8
 
9
- var _chunkYCEMBJEMjs = require('./chunk-YCEMBJEM.js');
9
+ var _chunkNM5BWVVBjs = require('./chunk-NM5BWVVB.js');
10
10
  require('./chunk-3LFH2WCF.js');
11
11
  require('./chunk-VQ4DZOBB.js');
12
12
 
@@ -23,7 +23,7 @@ var RemoteHttpInterceptor = class extends _chunkMVPEJK4Vjs.BatchInterceptor {
23
23
  name: "remote-interceptor",
24
24
  interceptors: [
25
25
  new (0, _chunkOOSIWXHXjs.ClientRequestInterceptor)(),
26
- new (0, _chunkYCEMBJEMjs.XMLHttpRequestInterceptor)()
26
+ new (0, _chunkNM5BWVVBjs.XMLHttpRequestInterceptor)()
27
27
  ]
28
28
  });
29
29
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-PSIO3L7D.mjs";
7
7
  import {
8
8
  XMLHttpRequestInterceptor
9
- } from "./chunk-UWSK5F3S.mjs";
9
+ } from "./chunk-SOWOSKLO.mjs";
10
10
  import "./chunk-7II4SWKS.mjs";
11
11
  import "./chunk-GFH37L5D.mjs";
12
12
  import {
@@ -204,8 +204,10 @@ function parseJson(data) {
204
204
  }
205
205
 
206
206
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
207
+ var statusCodesWithoutBody = [204, 205, 304];
207
208
  function createResponse(request, body) {
208
- return new Response(body, {
209
+ const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
210
+ return new Response(responseBodyOrNull, {
209
211
  status: request.status,
210
212
  statusText: request.statusText,
211
213
  headers: createHeadersFromXMLHttpReqestHeaders(
@@ -204,8 +204,10 @@ function parseJson(data) {
204
204
  }
205
205
 
206
206
  // src/interceptors/XMLHttpRequest/utils/createResponse.ts
207
+ var statusCodesWithoutBody = [204, 205, 304];
207
208
  function createResponse(request, body) {
208
- return new Response(body, {
209
+ const responseBodyOrNull = statusCodesWithoutBody.includes(request.status) ? null : body;
210
+ return new Response(responseBodyOrNull, {
209
211
  status: request.status,
210
212
  statusText: request.statusText,
211
213
  headers: createHeadersFromXMLHttpReqestHeaders(
@@ -1,10 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkYCEMBJEMjs = require('../../chunk-YCEMBJEM.js');
3
+ var _chunkNM5BWVVBjs = require('../../chunk-NM5BWVVB.js');
4
4
  require('../../chunk-3LFH2WCF.js');
5
5
  require('../../chunk-VQ4DZOBB.js');
6
6
  require('../../chunk-ZJOF5MEZ.js');
7
7
  require('../../chunk-XYZRP5S2.js');
8
8
 
9
9
 
10
- exports.XMLHttpRequestInterceptor = _chunkYCEMBJEMjs.XMLHttpRequestInterceptor;
10
+ exports.XMLHttpRequestInterceptor = _chunkNM5BWVVBjs.XMLHttpRequestInterceptor;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  XMLHttpRequestInterceptor
3
- } from "../../chunk-UWSK5F3S.mjs";
3
+ } from "../../chunk-SOWOSKLO.mjs";
4
4
  import "../../chunk-7II4SWKS.mjs";
5
5
  import "../../chunk-GFH37L5D.mjs";
6
6
  import "../../chunk-STA6QBYM.mjs";
@@ -10,6 +10,7 @@ var _chunkZJOF5MEZjs = require('../../chunk-ZJOF5MEZ.js');
10
10
  var _chunkXYZRP5S2js = require('../../chunk-XYZRP5S2.js');
11
11
 
12
12
  // src/interceptors/fetch/index.ts
13
+ var _deferredpromise = require('@open-draft/deferred-promise');
13
14
  var _outvariant = require('outvariant');
14
15
  var _until = require('@open-draft/until');
15
16
  var _FetchInterceptor = class extends _chunkXYZRP5S2js.Interceptor {
@@ -40,18 +41,31 @@ var _FetchInterceptor = class extends _chunkXYZRP5S2js.Interceptor {
40
41
  requestId
41
42
  });
42
43
  this.logger.info("awaiting for the mocked response...");
44
+ const signal = interactiveRequest.signal;
45
+ const requestAborted = new (0, _deferredpromise.DeferredPromise)();
46
+ signal.addEventListener(
47
+ "abort",
48
+ () => {
49
+ requestAborted.reject(signal.reason);
50
+ },
51
+ { once: true }
52
+ );
43
53
  const resolverResult = await _until.until.call(void 0, async () => {
44
- await this.emitter.untilIdle(
54
+ const allListenersResolved = this.emitter.untilIdle(
45
55
  "request",
46
56
  ({ args: [{ requestId: pendingRequestId }] }) => {
47
57
  return pendingRequestId === requestId;
48
58
  }
49
59
  );
60
+ await Promise.race([requestAborted, allListenersResolved]);
50
61
  this.logger.info("all request listeners have been resolved!");
51
62
  const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
52
63
  this.logger.info("event.respondWith called with:", mockedResponse2);
53
64
  return mockedResponse2;
54
65
  });
66
+ if (requestAborted.state === "rejected") {
67
+ return Promise.reject(requestAborted.rejectionReason);
68
+ }
55
69
  if (resolverResult.error) {
56
70
  const error = Object.assign(new TypeError("Failed to fetch"), {
57
71
  cause: resolverResult.error
@@ -10,6 +10,7 @@ import {
10
10
  } from "../../chunk-RGYCLCLK.mjs";
11
11
 
12
12
  // src/interceptors/fetch/index.ts
13
+ import { DeferredPromise } from "@open-draft/deferred-promise";
13
14
  import { invariant } from "outvariant";
14
15
  import { until } from "@open-draft/until";
15
16
  var _FetchInterceptor = class extends Interceptor {
@@ -40,18 +41,31 @@ var _FetchInterceptor = class extends Interceptor {
40
41
  requestId
41
42
  });
42
43
  this.logger.info("awaiting for the mocked response...");
44
+ const signal = interactiveRequest.signal;
45
+ const requestAborted = new DeferredPromise();
46
+ signal.addEventListener(
47
+ "abort",
48
+ () => {
49
+ requestAborted.reject(signal.reason);
50
+ },
51
+ { once: true }
52
+ );
43
53
  const resolverResult = await until(async () => {
44
- await this.emitter.untilIdle(
54
+ const allListenersResolved = this.emitter.untilIdle(
45
55
  "request",
46
56
  ({ args: [{ requestId: pendingRequestId }] }) => {
47
57
  return pendingRequestId === requestId;
48
58
  }
49
59
  );
60
+ await Promise.race([requestAborted, allListenersResolved]);
50
61
  this.logger.info("all request listeners have been resolved!");
51
62
  const [mockedResponse2] = await interactiveRequest.respondWith.invoked();
52
63
  this.logger.info("event.respondWith called with:", mockedResponse2);
53
64
  return mockedResponse2;
54
65
  });
66
+ if (requestAborted.state === "rejected") {
67
+ return Promise.reject(requestAborted.rejectionReason);
68
+ }
55
69
  if (resolverResult.error) {
56
70
  const error = Object.assign(new TypeError("Failed to fetch"), {
57
71
  cause: resolverResult.error
@@ -3,7 +3,7 @@
3
3
  var _chunkOOSIWXHXjs = require('../chunk-OOSIWXHX.js');
4
4
 
5
5
 
6
- var _chunkYCEMBJEMjs = require('../chunk-YCEMBJEM.js');
6
+ var _chunkNM5BWVVBjs = require('../chunk-NM5BWVVB.js');
7
7
  require('../chunk-3LFH2WCF.js');
8
8
  require('../chunk-VQ4DZOBB.js');
9
9
  require('../chunk-ZJOF5MEZ.js');
@@ -12,7 +12,7 @@ require('../chunk-XYZRP5S2.js');
12
12
  // src/presets/node.ts
13
13
  var node_default = [
14
14
  new (0, _chunkOOSIWXHXjs.ClientRequestInterceptor)(),
15
- new (0, _chunkYCEMBJEMjs.XMLHttpRequestInterceptor)()
15
+ new (0, _chunkNM5BWVVBjs.XMLHttpRequestInterceptor)()
16
16
  ];
17
17
 
18
18
 
@@ -3,7 +3,7 @@ import {
3
3
  } from "../chunk-PSIO3L7D.mjs";
4
4
  import {
5
5
  XMLHttpRequestInterceptor
6
- } from "../chunk-UWSK5F3S.mjs";
6
+ } from "../chunk-SOWOSKLO.mjs";
7
7
  import "../chunk-7II4SWKS.mjs";
8
8
  import "../chunk-GFH37L5D.mjs";
9
9
  import "../chunk-STA6QBYM.mjs";
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.24.0",
4
+ "version": "0.24.1",
5
5
  "main": "./lib/node/index.js",
6
6
  "module": "./lib/node/index.mjs",
7
7
  "types": "./lib/node/index.d.ts",
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "./RemoteHttpInterceptor": {
47
47
  "browser": null,
48
- "types": "./lib/node/interceptors/RemoteHttpInterceptor.d.ts",
49
- "require": "./lib/node/interceptors/RemoteHttpInterceptor.js",
50
- "import": "./lib/node/interceptors/RemoteHttpInterceptor.mjs",
51
- "default": "./lib/node/interceptors/RemoteHttpInterceptor.js"
48
+ "types": "./lib/node/RemoteHttpInterceptor.d.ts",
49
+ "require": "./lib/node/RemoteHttpInterceptor.js",
50
+ "import": "./lib/node/RemoteHttpInterceptor.mjs",
51
+ "default": "./lib/node/RemoteHttpInterceptor.js"
52
52
  },
53
53
  "./presets/node": {
54
54
  "browser": null,
@@ -3,6 +3,7 @@ import http from 'http'
3
3
  import { HttpServer } from '@open-draft/test-server/http'
4
4
  import { DeferredPromise } from '@open-draft/deferred-promise'
5
5
  import { ClientRequestInterceptor } from '.'
6
+ import { sleep } from '../../../test/helpers'
6
7
 
7
8
  const httpServer = new HttpServer((app) => {
8
9
  app.get('/', (_req, res) => {
@@ -55,3 +56,30 @@ it('forbids calling "respondWith" multiple times for the same request', async ()
55
56
  expect(response.statusCode).toBe(200)
56
57
  expect(response.statusMessage).toBe('')
57
58
  })
59
+
60
+
61
+ it('abort the request if the abort signal is emitted', async () => {
62
+ const requestUrl = httpServer.http.url('/')
63
+
64
+ const requestEmitted = new DeferredPromise<void>()
65
+ interceptor.on('request', async function delayedResponse({ request }) {
66
+ requestEmitted.resolve()
67
+ await sleep(10000)
68
+ request.respondWith(new Response())
69
+ })
70
+
71
+ const abortController = new AbortController()
72
+ const request = http.get(requestUrl, { signal: abortController.signal })
73
+
74
+ await requestEmitted
75
+
76
+ abortController.abort()
77
+
78
+ const requestAborted = new DeferredPromise<void>()
79
+ request.on('error', function(err) {
80
+ expect(err.name).toEqual('AbortError')
81
+ requestAborted.resolve()
82
+ })
83
+
84
+ await requestAborted
85
+ })
@@ -1,3 +1,5 @@
1
+ const statusCodesWithoutBody = [204, 205, 304]
2
+
1
3
  /**
2
4
  * Creates a Fetch API `Response` instance from the given
3
5
  * `XMLHttpRequest` instance and a response body.
@@ -6,7 +8,19 @@ export function createResponse(
6
8
  request: XMLHttpRequest,
7
9
  body: BodyInit | null
8
10
  ): Response {
9
- return new Response(body, {
11
+ /**
12
+ * Handle XMLHttpRequest responses that must have null as the
13
+ * response body when represented using Fetch API Response.
14
+ * XMLHttpRequest response will always have an empty string
15
+ * as the "request.response" in those cases, resulting in an error
16
+ * when constructing a Response instance.
17
+ * @see https://github.com/mswjs/interceptors/issues/379
18
+ */
19
+ const responseBodyOrNull = statusCodesWithoutBody.includes(request.status)
20
+ ? null
21
+ : body
22
+
23
+ return new Response(responseBodyOrNull, {
10
24
  status: request.status,
11
25
  statusText: request.statusText,
12
26
  headers: createHeadersFromXMLHttpReqestHeaders(
@@ -1,3 +1,4 @@
1
+ import { DeferredPromise } from '@open-draft/deferred-promise'
1
2
  import { invariant } from 'outvariant'
2
3
  import { until } from '@open-draft/until'
3
4
  import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
@@ -46,13 +47,27 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
46
47
 
47
48
  this.logger.info('awaiting for the mocked response...')
48
49
 
50
+ const signal = interactiveRequest.signal
51
+ const requestAborted = new DeferredPromise()
52
+
53
+ signal.addEventListener(
54
+ 'abort',
55
+ () => {
56
+ requestAborted.reject(signal.reason)
57
+ },
58
+ { once: true }
59
+ )
60
+
49
61
  const resolverResult = await until(async () => {
50
- await this.emitter.untilIdle(
62
+ const allListenersResolved = this.emitter.untilIdle(
51
63
  'request',
52
64
  ({ args: [{ requestId: pendingRequestId }] }) => {
53
65
  return pendingRequestId === requestId
54
66
  }
55
67
  )
68
+
69
+ await Promise.race([requestAborted, allListenersResolved])
70
+
56
71
  this.logger.info('all request listeners have been resolved!')
57
72
 
58
73
  const [mockedResponse] = await interactiveRequest.respondWith.invoked()
@@ -61,10 +76,15 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
61
76
  return mockedResponse
62
77
  })
63
78
 
79
+ if (requestAborted.state === 'rejected') {
80
+ return Promise.reject(requestAborted.rejectionReason)
81
+ }
82
+
64
83
  if (resolverResult.error) {
65
84
  const error = Object.assign(new TypeError('Failed to fetch'), {
66
85
  cause: resolverResult.error,
67
86
  })
87
+
68
88
  return Promise.reject(error)
69
89
  }
70
90