@mswjs/interceptors 0.31.1 → 0.32.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.
Files changed (69) hide show
  1. package/README.md +56 -39
  2. package/lib/node/RemoteHttpInterceptor.d.ts +1 -2
  3. package/lib/node/RemoteHttpInterceptor.js +11 -11
  4. package/lib/node/RemoteHttpInterceptor.mjs +5 -5
  5. package/lib/node/{chunk-LTEXDYJ6.js → chunk-2COJKQQB.js} +3 -3
  6. package/lib/node/chunk-3OJLYEWA.mjs +963 -0
  7. package/lib/node/chunk-3OJLYEWA.mjs.map +1 -0
  8. package/lib/node/chunk-5JMJ55U7.js +963 -0
  9. package/lib/node/chunk-5JMJ55U7.js.map +1 -0
  10. package/lib/node/{chunk-E4AC7YAC.js → chunk-BFLYGQ6D.js} +4 -2
  11. package/lib/node/{chunk-KSHIDGUL.mjs → chunk-DV4PBH4D.mjs} +3 -3
  12. package/lib/node/{chunk-OUWBQF3Z.mjs → chunk-KWV3JXSI.mjs} +14 -14
  13. package/lib/node/chunk-KWV3JXSI.mjs.map +1 -0
  14. package/lib/node/{chunk-6FRASLM3.mjs → chunk-PNWPIDEL.mjs} +2 -2
  15. package/lib/node/{chunk-APT7KA3B.js → chunk-PYD4E2EJ.js} +13 -13
  16. package/lib/node/{chunk-Q7POAM5N.mjs → chunk-TGTPXCLF.mjs} +3 -1
  17. package/lib/node/{chunk-MQJ3JOOK.js → chunk-UXCYRE4F.js} +14 -14
  18. package/lib/node/chunk-UXCYRE4F.js.map +1 -0
  19. package/lib/node/index.js +3 -3
  20. package/lib/node/index.mjs +2 -2
  21. package/lib/node/interceptors/ClientRequest/index.d.ts +83 -14
  22. package/lib/node/interceptors/ClientRequest/index.js +4 -4
  23. package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
  24. package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
  25. package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
  26. package/lib/node/interceptors/fetch/index.js +10 -10
  27. package/lib/node/interceptors/fetch/index.mjs +2 -2
  28. package/lib/node/presets/node.d.ts +2 -3
  29. package/lib/node/presets/node.js +6 -6
  30. package/lib/node/presets/node.mjs +4 -4
  31. package/package.json +2 -2
  32. package/src/interceptors/ClientRequest/MockHttpSocket.ts +595 -0
  33. package/src/interceptors/ClientRequest/agents.ts +78 -0
  34. package/src/interceptors/ClientRequest/index.test.ts +14 -12
  35. package/src/interceptors/ClientRequest/index.ts +200 -41
  36. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +78 -98
  37. package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +40 -22
  38. package/src/interceptors/Socket/MockSocket.test.ts +264 -0
  39. package/src/interceptors/Socket/MockSocket.ts +59 -0
  40. package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +26 -0
  41. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +52 -0
  42. package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +33 -0
  43. package/src/interceptors/Socket/utils/parseRawHeaders.ts +10 -0
  44. package/lib/node/chunk-IS3CIGXU.js +0 -909
  45. package/lib/node/chunk-IS3CIGXU.js.map +0 -1
  46. package/lib/node/chunk-MQJ3JOOK.js.map +0 -1
  47. package/lib/node/chunk-OMOWHUE6.mjs +0 -909
  48. package/lib/node/chunk-OMOWHUE6.mjs.map +0 -1
  49. package/lib/node/chunk-OUWBQF3Z.mjs.map +0 -1
  50. package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +0 -206
  51. package/src/interceptors/ClientRequest/NodeClientRequest.ts +0 -680
  52. package/src/interceptors/ClientRequest/http.get.ts +0 -30
  53. package/src/interceptors/ClientRequest/http.request.ts +0 -27
  54. package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +0 -26
  55. package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.ts +0 -74
  56. package/src/interceptors/ClientRequest/utils/createRequest.test.ts +0 -144
  57. package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -51
  58. package/src/interceptors/ClientRequest/utils/createResponse.test.ts +0 -53
  59. package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -55
  60. package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +0 -41
  61. package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.ts +0 -53
  62. package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +0 -36
  63. package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.ts +0 -39
  64. /package/lib/node/{chunk-LTEXDYJ6.js.map → chunk-2COJKQQB.js.map} +0 -0
  65. /package/lib/node/{chunk-E4AC7YAC.js.map → chunk-BFLYGQ6D.js.map} +0 -0
  66. /package/lib/node/{chunk-KSHIDGUL.mjs.map → chunk-DV4PBH4D.mjs.map} +0 -0
  67. /package/lib/node/{chunk-6FRASLM3.mjs.map → chunk-PNWPIDEL.mjs.map} +0 -0
  68. /package/lib/node/{chunk-APT7KA3B.js.map → chunk-PYD4E2EJ.js.map} +0 -0
  69. /package/lib/node/{chunk-Q7POAM5N.mjs.map → chunk-TGTPXCLF.mjs.map} +0 -0
package/README.md CHANGED
@@ -11,81 +11,98 @@ This library supports intercepting the following protocols:
11
11
 
12
12
  ## Motivation
13
13
 
14
- While there are a lot of network communication mocking libraries, they tend to use request interception as an implementation detail, giving you a high-level API that includes request matching, timeouts, retries, and so forth.
14
+ While there are a lot of network mocking libraries, they tend to use request interception as an implementation detail, giving you a high-level API that includes request matching, timeouts, recording, and so forth.
15
15
 
16
- This library is a strip-to-bone implementation that provides as little abstraction as possible to execute arbitrary logic upon any request. It's primarily designed as an underlying component for high-level API mocking solutions such as [Mock Service Worker](https://github.com/mswjs/msw).
16
+ This library is a barebones implementation that provides as little abstraction as possible to execute arbitrary logic upon any request. It's primarily designed as an underlying component for high-level API mocking solutions such as [Mock Service Worker](https://github.com/mswjs/msw).
17
17
 
18
18
  ### How is this library different?
19
19
 
20
20
  A traditional API mocking implementation in Node.js looks roughly like this:
21
21
 
22
22
  ```js
23
- import http from 'http'
24
-
25
- function applyMock() {
26
- // Store the original request module.
27
- const originalHttpRequest = http.request
28
-
29
- // Rewrite the request module entirely.
30
- http.request = function (...args) {
31
- // Decide whether to handle this request before
32
- // the actual request happens.
33
- if (shouldMock(args)) {
34
- // If so, never create a request, respond to it
35
- // using the mocked response from this blackbox.
36
- return coerceToResponse.bind(this, mock)
37
- }
38
-
39
- // Otherwise, construct the original request
40
- // and perform it as-is (receives the original response).
41
- return originalHttpRequest(...args)
23
+ import http from 'node:http'
24
+
25
+ // Store the original request function.
26
+ const originalHttpRequest = http.request
27
+
28
+ // Override the request function entirely.
29
+ http.request = function (...args) {
30
+ // Decide if the outgoing request matches a predicate.
31
+ if (predicate(args)) {
32
+ // If it does, never create a request, respond to it
33
+ // using the mocked response from this blackbox.
34
+ return coerceToResponse.bind(this, mock)
42
35
  }
36
+
37
+ // Otherwise, construct the original request
38
+ // and perform it as-is.
39
+ return originalHttpRequest(...args)
43
40
  }
44
41
  ```
45
42
 
46
- This library deviates from such implementation and uses _class extensions_ instead of module rewrites. Such deviation is necessary because, unlike other solutions that include request matching and can determine whether to mock requests _before_ they actually happen, this library is not opinionated about the mocked/bypassed nature of the requests. Instead, it _intercepts all requests_ and delegates the decision of mocking to the end consumer.
43
+ The core philosophy of Interceptors is to _run as much of the underlying network code as possible_. Strange for a network mocking library, isn't it? Turns out, respecting the system's integrity and executing more of the network code leads to more resilient tests and also helps to uncover bugs in the code that would otherwise go unnoticed.
44
+
45
+ Interceptors heavily rely on _class extension_ instead of function and module overrides. By extending the native network code, it can surgically insert the interception and mocking pieces only where necessary, leaving the rest of the system intact.
47
46
 
48
47
  ```js
49
- class NodeClientRequest extends ClientRequest {
50
- async end(...args) {
51
- // Check if there's a mocked response for this request.
52
- // You control this in the "resolver" function.
53
- const mockedResponse = await resolver(request)
54
-
55
- // If there is a mocked response, use it to respond to this
56
- // request, finalizing it afterward as if it received that
57
- // response from the actual server it connected to.
48
+ class XMLHttpRequestProxy extends XMLHttpRequest {
49
+ async send() {
50
+ // Call the request listeners and see if any of them
51
+ // returns a mocked response for this request.
52
+ const mockedResponse = await waitForRequestListeners({ request })
53
+
54
+ // If there is a mocked response, use it. This actually
55
+ // transitions the XMLHttpRequest instance into the correct
56
+ // response state (below is a simplified illustration).
58
57
  if (mockedResponse) {
59
- this.respondWith(mockedResponse)
60
- this.finish()
58
+ // Handle the response headers.
59
+ this.request.status = mockedResponse.status
60
+ this.request.statusText = mockedResponse.statusText
61
+ this.request.responseUrl = mockedResponse.url
62
+ this.readyState = 2
63
+ this.trigger('readystatechange')
64
+
65
+ // Start streaming the response body.
66
+ this.trigger('loadstart')
67
+ this.readyState = 3
68
+ this.trigger('readystatechange')
69
+ await streamResponseBody(mockedResponse)
70
+
71
+ // Finish the response.
72
+ this.trigger('load')
73
+ this.trigger('loadend')
74
+ this.readyState = 4
61
75
  return
62
76
  }
63
77
 
64
- // Otherwise, perform the original "ClientRequest.prototype.end" call.
65
- return super.end(...args)
78
+ // Otherwise, perform the original "XMLHttpRequest.prototype.send" call.
79
+ return super.send(...args)
66
80
  }
67
81
  }
68
82
  ```
69
83
 
70
- By extending the native modules, this library actually constructs requests as soon as they are constructed by the consumer. This enables all the request input validation and transformations done natively by Node.jssomething that traditional solutions simply cannot do (they replace `http.ClientRequest` entirely). The class extension allows to fully utilize Node.js internals instead of polyfilling them, which results in more resilient mocks.
84
+ > The request interception algorithms differ dramatically based on the request API. Interceptors acommodate for them all, bringing the intercepted requests to a common groundthe Fetch API `Request` instance. The same applies for responses, where a Fetch API `Response` instance is translated to the appropriate response format.
85
+
86
+ This library aims to provide _full specification compliance_ with the APIs and protocols it extends.
71
87
 
72
88
  ## What this library does
73
89
 
74
- This library extends (or patches, where applicable) the following native modules:
90
+ This library extends the following native modules:
75
91
 
76
92
  - `http.get`/`http.request`
77
93
  - `https.get`/`https.request`
78
94
  - `XMLHttpRequest`
79
95
  - `fetch`
96
+ - `WebSocket`
80
97
 
81
98
  Once extended, it intercepts and normalizes all requests to the Fetch API `Request` instances. This way, no matter the request source (`http.ClientRequest`, `XMLHttpRequest`, `window.Request`, etc), you always get a specification-compliant request instance to work with.
82
99
 
83
- You can respond to the intercepted request by constructing a Fetch API Response instance. Instead of designing custom abstractions, this library respects the Fetch API specification and takes the responsibility to coerce a single response declaration to the appropriate response formats based on the request-issuing modules (like `http.OutgoingMessage` to respond to `http.ClientRequest`, or updating `XMLHttpRequest` response-related properties).
100
+ You can respond to the intercepted HTTP request by constructing a Fetch API Response instance. Instead of designing custom abstractions, this library respects the Fetch API specification and takes the responsibility to coerce a single response declaration to the appropriate response formats based on the request-issuing modules (like `http.OutgoingMessage` to respond to `http.ClientRequest`, or updating `XMLHttpRequest` response-related properties).
84
101
 
85
102
  ## What this library doesn't do
86
103
 
87
104
  - Does **not** provide any request matching logic;
88
- - Does **not** decide how to handle requests.
105
+ - Does **not** handle requests by default.
89
106
 
90
107
  ## Getting started
91
108
 
@@ -6,8 +6,7 @@ import { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest/index.j
6
6
  import '@open-draft/deferred-promise';
7
7
  import '@open-draft/logger';
8
8
  import 'strict-event-emitter';
9
- import 'http';
10
- import 'https';
9
+ import 'node:net';
11
10
 
12
11
  interface SerializedRequest {
13
12
  id: string;
@@ -1,30 +1,30 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkLTEXDYJ6js = require('./chunk-LTEXDYJ6.js');
3
+ var _chunk2COJKQQBjs = require('./chunk-2COJKQQB.js');
4
4
 
5
5
 
6
- var _chunkIS3CIGXUjs = require('./chunk-IS3CIGXU.js');
6
+ var _chunk5JMJ55U7js = require('./chunk-5JMJ55U7.js');
7
7
 
8
8
 
9
- var _chunkAPT7KA3Bjs = require('./chunk-APT7KA3B.js');
9
+ var _chunkPYD4E2EJjs = require('./chunk-PYD4E2EJ.js');
10
10
  require('./chunk-LK6DILFK.js');
11
11
  require('./chunk-EIBTX65O.js');
12
12
 
13
13
 
14
14
 
15
- var _chunkMQJ3JOOKjs = require('./chunk-MQJ3JOOK.js');
15
+ var _chunkUXCYRE4Fjs = require('./chunk-UXCYRE4F.js');
16
16
 
17
17
 
18
- var _chunkE4AC7YACjs = require('./chunk-E4AC7YAC.js');
18
+ var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
19
19
 
20
20
  // src/RemoteHttpInterceptor.ts
21
- var RemoteHttpInterceptor = class extends _chunkLTEXDYJ6js.BatchInterceptor {
21
+ var RemoteHttpInterceptor = class extends _chunk2COJKQQBjs.BatchInterceptor {
22
22
  constructor() {
23
23
  super({
24
24
  name: "remote-interceptor",
25
25
  interceptors: [
26
- new (0, _chunkIS3CIGXUjs.ClientRequestInterceptor)(),
27
- new (0, _chunkAPT7KA3Bjs.XMLHttpRequestInterceptor)()
26
+ new (0, _chunk5JMJ55U7js.ClientRequestInterceptor)(),
27
+ new (0, _chunkPYD4E2EJjs.XMLHttpRequestInterceptor)()
28
28
  ]
29
29
  });
30
30
  }
@@ -91,7 +91,7 @@ function requestReviver(key, value) {
91
91
  return value;
92
92
  }
93
93
  }
94
- var _RemoteHttpResolver = class extends _chunkE4AC7YACjs.Interceptor {
94
+ var _RemoteHttpResolver = class extends _chunkBFLYGQ6Djs.Interceptor {
95
95
  constructor(options) {
96
96
  super(_RemoteHttpResolver.symbol);
97
97
  this.process = options.process;
@@ -119,13 +119,13 @@ var _RemoteHttpResolver = class extends _chunkE4AC7YACjs.Interceptor {
119
119
  credentials: requestJson.credentials,
120
120
  body: requestJson.body
121
121
  });
122
- const { interactiveRequest, requestController } = _chunkMQJ3JOOKjs.toInteractiveRequest.call(void 0, capturedRequest);
122
+ const { interactiveRequest, requestController } = _chunkUXCYRE4Fjs.toInteractiveRequest.call(void 0, capturedRequest);
123
123
  this.emitter.once("request", () => {
124
124
  if (requestController.responsePromise.state === "pending") {
125
125
  requestController.respondWith(void 0);
126
126
  }
127
127
  });
128
- await _chunkMQJ3JOOKjs.emitAsync.call(void 0, this.emitter, "request", {
128
+ await _chunkUXCYRE4Fjs.emitAsync.call(void 0, this.emitter, "request", {
129
129
  request: interactiveRequest,
130
130
  requestId: requestJson.id
131
131
  });
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  BatchInterceptor
3
- } from "./chunk-6FRASLM3.mjs";
3
+ } from "./chunk-PNWPIDEL.mjs";
4
4
  import {
5
5
  ClientRequestInterceptor
6
- } from "./chunk-OMOWHUE6.mjs";
6
+ } from "./chunk-3OJLYEWA.mjs";
7
7
  import {
8
8
  XMLHttpRequestInterceptor
9
- } from "./chunk-KSHIDGUL.mjs";
9
+ } from "./chunk-DV4PBH4D.mjs";
10
10
  import "./chunk-6HYIRFX2.mjs";
11
11
  import "./chunk-OJ6O4LSC.mjs";
12
12
  import {
13
13
  emitAsync,
14
14
  toInteractiveRequest
15
- } from "./chunk-OUWBQF3Z.mjs";
15
+ } from "./chunk-KWV3JXSI.mjs";
16
16
  import {
17
17
  Interceptor
18
- } from "./chunk-Q7POAM5N.mjs";
18
+ } from "./chunk-TGTPXCLF.mjs";
19
19
 
20
20
  // src/RemoteHttpInterceptor.ts
21
21
  var RemoteHttpInterceptor = class extends BatchInterceptor {
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkE4AC7YACjs = require('./chunk-E4AC7YAC.js');
3
+ var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
4
4
 
5
5
  // src/BatchInterceptor.ts
6
- var BatchInterceptor = class extends _chunkE4AC7YACjs.Interceptor {
6
+ var BatchInterceptor = class extends _chunkBFLYGQ6Djs.Interceptor {
7
7
  constructor(options) {
8
8
  BatchInterceptor.symbol = Symbol(options.name);
9
9
  super(BatchInterceptor.symbol);
@@ -48,4 +48,4 @@ var BatchInterceptor = class extends _chunkE4AC7YACjs.Interceptor {
48
48
 
49
49
 
50
50
  exports.BatchInterceptor = BatchInterceptor;
51
- //# sourceMappingURL=chunk-LTEXDYJ6.js.map
51
+ //# sourceMappingURL=chunk-2COJKQQB.js.map