@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.
- package/README.md +56 -39
- package/lib/node/RemoteHttpInterceptor.d.ts +1 -2
- package/lib/node/RemoteHttpInterceptor.js +11 -11
- package/lib/node/RemoteHttpInterceptor.mjs +5 -5
- package/lib/node/{chunk-LTEXDYJ6.js → chunk-2COJKQQB.js} +3 -3
- package/lib/node/chunk-3OJLYEWA.mjs +963 -0
- package/lib/node/chunk-3OJLYEWA.mjs.map +1 -0
- package/lib/node/chunk-5JMJ55U7.js +963 -0
- package/lib/node/chunk-5JMJ55U7.js.map +1 -0
- package/lib/node/{chunk-E4AC7YAC.js → chunk-BFLYGQ6D.js} +4 -2
- package/lib/node/{chunk-KSHIDGUL.mjs → chunk-DV4PBH4D.mjs} +3 -3
- package/lib/node/{chunk-OUWBQF3Z.mjs → chunk-KWV3JXSI.mjs} +14 -14
- package/lib/node/chunk-KWV3JXSI.mjs.map +1 -0
- package/lib/node/{chunk-6FRASLM3.mjs → chunk-PNWPIDEL.mjs} +2 -2
- package/lib/node/{chunk-APT7KA3B.js → chunk-PYD4E2EJ.js} +13 -13
- package/lib/node/{chunk-Q7POAM5N.mjs → chunk-TGTPXCLF.mjs} +3 -1
- package/lib/node/{chunk-MQJ3JOOK.js → chunk-UXCYRE4F.js} +14 -14
- package/lib/node/chunk-UXCYRE4F.js.map +1 -0
- package/lib/node/index.js +3 -3
- package/lib/node/index.mjs +2 -2
- package/lib/node/interceptors/ClientRequest/index.d.ts +83 -14
- package/lib/node/interceptors/ClientRequest/index.js +4 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +3 -3
- package/lib/node/interceptors/XMLHttpRequest/index.js +4 -4
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -3
- package/lib/node/interceptors/fetch/index.js +10 -10
- package/lib/node/interceptors/fetch/index.mjs +2 -2
- package/lib/node/presets/node.d.ts +2 -3
- package/lib/node/presets/node.js +6 -6
- package/lib/node/presets/node.mjs +4 -4
- package/package.json +2 -2
- package/src/interceptors/ClientRequest/MockHttpSocket.ts +595 -0
- package/src/interceptors/ClientRequest/agents.ts +78 -0
- package/src/interceptors/ClientRequest/index.test.ts +14 -12
- package/src/interceptors/ClientRequest/index.ts +200 -41
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +78 -98
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +40 -22
- package/src/interceptors/Socket/MockSocket.test.ts +264 -0
- package/src/interceptors/Socket/MockSocket.ts +59 -0
- package/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +26 -0
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts +52 -0
- package/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +33 -0
- package/src/interceptors/Socket/utils/parseRawHeaders.ts +10 -0
- package/lib/node/chunk-IS3CIGXU.js +0 -909
- package/lib/node/chunk-IS3CIGXU.js.map +0 -1
- package/lib/node/chunk-MQJ3JOOK.js.map +0 -1
- package/lib/node/chunk-OMOWHUE6.mjs +0 -909
- package/lib/node/chunk-OMOWHUE6.mjs.map +0 -1
- package/lib/node/chunk-OUWBQF3Z.mjs.map +0 -1
- package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +0 -206
- package/src/interceptors/ClientRequest/NodeClientRequest.ts +0 -680
- package/src/interceptors/ClientRequest/http.get.ts +0 -30
- package/src/interceptors/ClientRequest/http.request.ts +0 -27
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +0 -26
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.ts +0 -74
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +0 -144
- package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -51
- package/src/interceptors/ClientRequest/utils/createResponse.test.ts +0 -53
- package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -55
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +0 -41
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.ts +0 -53
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +0 -36
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.ts +0 -39
- /package/lib/node/{chunk-LTEXDYJ6.js.map → chunk-2COJKQQB.js.map} +0 -0
- /package/lib/node/{chunk-E4AC7YAC.js.map → chunk-BFLYGQ6D.js.map} +0 -0
- /package/lib/node/{chunk-KSHIDGUL.mjs.map → chunk-DV4PBH4D.mjs.map} +0 -0
- /package/lib/node/{chunk-6FRASLM3.mjs.map → chunk-PNWPIDEL.mjs.map} +0 -0
- /package/lib/node/{chunk-APT7KA3B.js.map → chunk-PYD4E2EJ.js.map} +0 -0
- /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
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
|
50
|
-
async
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
const mockedResponse = await
|
|
54
|
-
|
|
55
|
-
// If there is a mocked response, use it
|
|
56
|
-
//
|
|
57
|
-
// response
|
|
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
|
-
|
|
60
|
-
this.
|
|
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 "
|
|
65
|
-
return super.
|
|
78
|
+
// Otherwise, perform the original "XMLHttpRequest.prototype.send" call.
|
|
79
|
+
return super.send(...args)
|
|
66
80
|
}
|
|
67
81
|
}
|
|
68
82
|
```
|
|
69
83
|
|
|
70
|
-
|
|
84
|
+
> The request interception algorithms differ dramatically based on the request API. Interceptors acommodate for them all, bringing the intercepted requests to a common ground—the 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
|
|
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**
|
|
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 '
|
|
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
|
|
3
|
+
var _chunk2COJKQQBjs = require('./chunk-2COJKQQB.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunk5JMJ55U7js = require('./chunk-5JMJ55U7.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
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
|
|
15
|
+
var _chunkUXCYRE4Fjs = require('./chunk-UXCYRE4F.js');
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
|
|
19
19
|
|
|
20
20
|
// src/RemoteHttpInterceptor.ts
|
|
21
|
-
var RemoteHttpInterceptor = class extends
|
|
21
|
+
var RemoteHttpInterceptor = class extends _chunk2COJKQQBjs.BatchInterceptor {
|
|
22
22
|
constructor() {
|
|
23
23
|
super({
|
|
24
24
|
name: "remote-interceptor",
|
|
25
25
|
interceptors: [
|
|
26
|
-
new (0,
|
|
27
|
-
new (0,
|
|
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
|
|
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 } =
|
|
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
|
|
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-
|
|
3
|
+
} from "./chunk-PNWPIDEL.mjs";
|
|
4
4
|
import {
|
|
5
5
|
ClientRequestInterceptor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3OJLYEWA.mjs";
|
|
7
7
|
import {
|
|
8
8
|
XMLHttpRequestInterceptor
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
15
|
+
} from "./chunk-KWV3JXSI.mjs";
|
|
16
16
|
import {
|
|
17
17
|
Interceptor
|
|
18
|
-
} from "./chunk-
|
|
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
|
|
3
|
+
var _chunkBFLYGQ6Djs = require('./chunk-BFLYGQ6D.js');
|
|
4
4
|
|
|
5
5
|
// src/BatchInterceptor.ts
|
|
6
|
-
var BatchInterceptor = class extends
|
|
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-
|
|
51
|
+
//# sourceMappingURL=chunk-2COJKQQB.js.map
|