@mswjs/interceptors 0.25.1 → 0.25.3
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/lib/browser/Interceptor-8d5fd4c6.d.ts +86 -0
- package/lib/browser/{chunk-ANLPTCZ5.mjs → chunk-AN3YI76R.mjs} +33 -26
- package/lib/browser/{chunk-4CFMDU7Z.js → chunk-CWVY2E3W.js} +20 -134
- package/lib/browser/{chunk-OSIUQA4X.js → chunk-FFBQOFWV.js} +38 -31
- package/lib/browser/{chunk-VMXB5F2J.mjs → chunk-HXJPKJY3.mjs} +25 -15
- package/lib/browser/{chunk-DBFLI5DJ.js → chunk-KITNLK66.js} +30 -20
- package/lib/browser/chunk-KK6APRON.mjs +58 -0
- package/lib/browser/{chunk-GXJLJMOT.mjs → chunk-QPMXOLDO.mjs} +21 -135
- package/lib/browser/chunk-X3NRJIZW.js +58 -0
- package/lib/browser/index.d.ts +7 -3
- package/lib/browser/index.js +24 -5
- package/lib/browser/index.mjs +22 -3
- package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +4 -3
- 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 +2 -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 +2 -1
- package/lib/browser/presets/browser.js +6 -6
- package/lib/browser/presets/browser.mjs +4 -4
- package/lib/node/{BatchInterceptor-c841b068.d.ts → BatchInterceptor-9785c567.d.ts} +5 -2
- package/lib/node/Interceptor-7a701c1f.d.ts +86 -0
- package/lib/node/RemoteHttpInterceptor.d.ts +3 -2
- package/lib/node/RemoteHttpInterceptor.js +19 -18
- package/lib/node/RemoteHttpInterceptor.mjs +15 -14
- package/lib/node/chunk-3IYIKC3X.mjs +6 -0
- package/lib/node/{chunk-XYZRP5S2.js → chunk-3XFLRXRY.js} +20 -134
- package/lib/node/chunk-5PTPJLB7.js +58 -0
- package/lib/node/{chunk-HSCXCLVT.mjs → chunk-FB53TMYN.mjs} +33 -26
- package/lib/node/{chunk-RGYCLCLK.mjs → chunk-GM3YBSM3.mjs} +21 -135
- package/lib/node/{chunk-E6YC337Q.js → chunk-JCWVLTP7.js} +35 -28
- package/lib/node/{chunk-OL7OR4RL.mjs → chunk-MCO3RLQC.mjs} +48 -26
- package/lib/node/{chunk-3MYUI4B2.js → chunk-NCHFM2TB.js} +50 -28
- package/lib/node/chunk-OGN3ZR35.js +6 -0
- package/lib/node/{chunk-VS3GJPUE.mjs → chunk-UBEFEZXT.mjs} +22 -3
- package/lib/node/{chunk-MVPEJK4V.js → chunk-UF7QIAQ5.js} +23 -4
- package/lib/node/chunk-YQGTMMOZ.mjs +58 -0
- package/lib/node/index.d.ts +3 -2
- package/lib/node/index.js +3 -3
- package/lib/node/index.mjs +2 -2
- package/lib/node/interceptors/ClientRequest/index.d.ts +4 -3
- package/lib/node/interceptors/ClientRequest/index.js +5 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +4 -3
- package/lib/node/interceptors/XMLHttpRequest/index.d.ts +4 -3
- package/lib/node/interceptors/XMLHttpRequest/index.js +5 -4
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +4 -3
- package/lib/node/interceptors/fetch/index.d.ts +2 -1
- package/lib/node/interceptors/fetch/index.js +27 -17
- package/lib/node/interceptors/fetch/index.mjs +25 -15
- package/lib/node/presets/node.d.ts +3 -2
- package/lib/node/presets/node.js +7 -6
- package/lib/node/presets/node.mjs +5 -4
- package/package.json +2 -2
- package/src/BatchInterceptor.test.ts +141 -0
- package/src/BatchInterceptor.ts +38 -4
- package/src/Interceptor.test.ts +46 -0
- package/src/Interceptor.ts +35 -16
- package/src/RemoteHttpInterceptor.ts +11 -9
- package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +10 -10
- package/src/interceptors/ClientRequest/NodeClientRequest.ts +80 -43
- package/src/interceptors/ClientRequest/http.get.ts +3 -1
- package/src/interceptors/ClientRequest/http.request.ts +3 -1
- package/src/interceptors/ClientRequest/index.test.ts +2 -3
- package/src/interceptors/ClientRequest/index.ts +2 -2
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +2 -2
- package/src/interceptors/ClientRequest/utils/createResponse.test.ts +23 -0
- package/src/interceptors/ClientRequest/utils/createResponse.ts +18 -13
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +29 -25
- package/src/interceptors/XMLHttpRequest/index.ts +2 -2
- package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +4 -2
- package/src/interceptors/fetch/index.ts +26 -13
- package/src/utils/RequestController.ts +21 -0
- package/src/utils/emitAsync.ts +25 -0
- package/src/utils/responseUtils.ts +5 -0
- package/src/utils/toInteractiveRequest.ts +17 -23
- package/lib/browser/Interceptor-0a020bc4.d.ts +0 -116
- package/lib/browser/chunk-PCFJD76X.js +0 -64
- package/lib/browser/chunk-RT3ATOJH.mjs +0 -64
- package/lib/node/Interceptor-738f79c5.d.ts +0 -116
- package/lib/node/chunk-STA6QBYM.mjs +0 -64
- package/lib/node/chunk-ZJOF5MEZ.js +0 -64
- package/src/utils/AsyncEventEmitter.test.ts +0 -102
- package/src/utils/AsyncEventEmitter.ts +0 -193
- package/src/utils/createLazyCallback.ts +0 -49
package/lib/node/presets/node.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkNCHFM2TBjs = require('../chunk-NCHFM2TB.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkJCWVLTP7js = require('../chunk-JCWVLTP7.js');
|
|
7
7
|
require('../chunk-3LFH2WCF.js');
|
|
8
|
+
require('../chunk-OGN3ZR35.js');
|
|
8
9
|
require('../chunk-VQ4DZOBB.js');
|
|
9
|
-
require('../chunk-
|
|
10
|
-
require('../chunk-
|
|
10
|
+
require('../chunk-5PTPJLB7.js');
|
|
11
|
+
require('../chunk-3XFLRXRY.js');
|
|
11
12
|
|
|
12
13
|
// src/presets/node.ts
|
|
13
14
|
var node_default = [
|
|
14
|
-
new (0,
|
|
15
|
-
new (0,
|
|
15
|
+
new (0, _chunkNCHFM2TBjs.ClientRequestInterceptor)(),
|
|
16
|
+
new (0, _chunkJCWVLTP7js.XMLHttpRequestInterceptor)()
|
|
16
17
|
];
|
|
17
18
|
|
|
18
19
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClientRequestInterceptor
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-MCO3RLQC.mjs";
|
|
4
4
|
import {
|
|
5
5
|
XMLHttpRequestInterceptor
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-FB53TMYN.mjs";
|
|
7
7
|
import "../chunk-7II4SWKS.mjs";
|
|
8
|
+
import "../chunk-3IYIKC3X.mjs";
|
|
8
9
|
import "../chunk-GFH37L5D.mjs";
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-YQGTMMOZ.mjs";
|
|
11
|
+
import "../chunk-GM3YBSM3.mjs";
|
|
11
12
|
|
|
12
13
|
// src/presets/node.ts
|
|
13
14
|
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.25.
|
|
4
|
+
"version": "0.25.3",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"@open-draft/until": "^2.0.0",
|
|
129
129
|
"is-node-process": "^1.2.0",
|
|
130
130
|
"outvariant": "^1.2.1",
|
|
131
|
-
"strict-event-emitter": "^0.5.
|
|
131
|
+
"strict-event-emitter": "^0.5.1"
|
|
132
132
|
},
|
|
133
133
|
"resolutions": {
|
|
134
134
|
"memfs": "^3.4.13"
|
|
@@ -112,3 +112,144 @@ it('disposes of child interceptors', async () => {
|
|
|
112
112
|
expect(primaryDisposeSpy).toHaveBeenCalledTimes(1)
|
|
113
113
|
expect(secondaryDisposeSpy).toHaveBeenCalledTimes(1)
|
|
114
114
|
})
|
|
115
|
+
|
|
116
|
+
it('forwards listeners added via "on()"', () => {
|
|
117
|
+
class FirstInterceptor extends Interceptor<any> {
|
|
118
|
+
constructor() {
|
|
119
|
+
super(Symbol('first'))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
class SecondaryInterceptor extends Interceptor<any> {
|
|
123
|
+
constructor() {
|
|
124
|
+
super(Symbol('second'))
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const firstInterceptor = new FirstInterceptor()
|
|
129
|
+
const secondInterceptor = new SecondaryInterceptor()
|
|
130
|
+
|
|
131
|
+
const interceptor = new BatchInterceptor({
|
|
132
|
+
name: 'batch',
|
|
133
|
+
interceptors: [firstInterceptor, secondInterceptor],
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const listener = vi.fn()
|
|
137
|
+
interceptor.on('foo', listener)
|
|
138
|
+
|
|
139
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1)
|
|
140
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1)
|
|
141
|
+
expect(interceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('forwards listeners removal via "off()"', () => {
|
|
145
|
+
type Events = {
|
|
146
|
+
foo: []
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class FirstInterceptor extends Interceptor<Events> {
|
|
150
|
+
constructor() {
|
|
151
|
+
super(Symbol('first'))
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
class SecondaryInterceptor extends Interceptor<Events> {
|
|
155
|
+
constructor() {
|
|
156
|
+
super(Symbol('second'))
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const firstInterceptor = new FirstInterceptor()
|
|
161
|
+
const secondInterceptor = new SecondaryInterceptor()
|
|
162
|
+
|
|
163
|
+
const interceptor = new BatchInterceptor({
|
|
164
|
+
name: 'batch',
|
|
165
|
+
interceptors: [firstInterceptor, secondInterceptor],
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const listener = vi.fn()
|
|
169
|
+
interceptor.on('foo', listener)
|
|
170
|
+
interceptor.off('foo', listener)
|
|
171
|
+
|
|
172
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
173
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('forwards removal of all listeners by name via ".removeAllListeners()"', () => {
|
|
177
|
+
type Events = {
|
|
178
|
+
foo: []
|
|
179
|
+
bar: []
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
class FirstInterceptor extends Interceptor<Events> {
|
|
183
|
+
constructor() {
|
|
184
|
+
super(Symbol('first'))
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
class SecondaryInterceptor extends Interceptor<Events> {
|
|
188
|
+
constructor() {
|
|
189
|
+
super(Symbol('second'))
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const firstInterceptor = new FirstInterceptor()
|
|
194
|
+
const secondInterceptor = new SecondaryInterceptor()
|
|
195
|
+
|
|
196
|
+
const interceptor = new BatchInterceptor({
|
|
197
|
+
name: 'batch',
|
|
198
|
+
interceptors: [firstInterceptor, secondInterceptor],
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
const listener = vi.fn()
|
|
202
|
+
interceptor.on('foo', listener)
|
|
203
|
+
interceptor.on('foo', listener)
|
|
204
|
+
interceptor.on('bar', listener)
|
|
205
|
+
|
|
206
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2)
|
|
207
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2)
|
|
208
|
+
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
209
|
+
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
210
|
+
|
|
211
|
+
interceptor.removeAllListeners('foo')
|
|
212
|
+
|
|
213
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
214
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
215
|
+
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
216
|
+
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('forwards removal of all listeners via ".removeAllListeners()"', () => {
|
|
220
|
+
class FirstInterceptor extends Interceptor<any> {
|
|
221
|
+
constructor() {
|
|
222
|
+
super(Symbol('first'))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
class SecondaryInterceptor extends Interceptor<any> {
|
|
226
|
+
constructor() {
|
|
227
|
+
super(Symbol('second'))
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const firstInterceptor = new FirstInterceptor()
|
|
232
|
+
const secondInterceptor = new SecondaryInterceptor()
|
|
233
|
+
|
|
234
|
+
const interceptor = new BatchInterceptor({
|
|
235
|
+
name: 'batch',
|
|
236
|
+
interceptors: [firstInterceptor, secondInterceptor],
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
const listener = vi.fn()
|
|
240
|
+
interceptor.on('foo', listener)
|
|
241
|
+
interceptor.on('foo', listener)
|
|
242
|
+
interceptor.on('bar', listener)
|
|
243
|
+
|
|
244
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2)
|
|
245
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2)
|
|
246
|
+
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
247
|
+
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
|
|
248
|
+
|
|
249
|
+
interceptor.removeAllListeners()
|
|
250
|
+
|
|
251
|
+
expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
252
|
+
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
|
|
253
|
+
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(0)
|
|
254
|
+
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(0)
|
|
255
|
+
})
|
package/src/BatchInterceptor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventMap, Listener } from 'strict-event-emitter'
|
|
2
|
-
import {
|
|
2
|
+
import { Interceptor, ExtractEventNames } from './Interceptor'
|
|
3
3
|
|
|
4
4
|
export interface BatchInterceptorOptions<
|
|
5
5
|
InterceptorList extends ReadonlyArray<Interceptor<any>>
|
|
@@ -51,11 +51,45 @@ export class BatchInterceptor<
|
|
|
51
51
|
public on<EventName extends ExtractEventNames<Events>>(
|
|
52
52
|
event: EventName,
|
|
53
53
|
listener: Listener<Events[EventName]>
|
|
54
|
-
) {
|
|
54
|
+
): this {
|
|
55
55
|
// Instead of adding a listener to the batch interceptor,
|
|
56
56
|
// propagate the listener to each of the individual interceptors.
|
|
57
|
-
this.interceptors
|
|
57
|
+
for (const interceptor of this.interceptors) {
|
|
58
58
|
interceptor.on(event, listener)
|
|
59
|
-
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return this
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public once<EventName extends ExtractEventNames<Events>>(
|
|
65
|
+
event: EventName,
|
|
66
|
+
listener: Listener<Events[EventName]>
|
|
67
|
+
): this {
|
|
68
|
+
for (const interceptor of this.interceptors) {
|
|
69
|
+
interceptor.once(event, listener)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public off<EventName extends ExtractEventNames<Events>>(
|
|
76
|
+
event: EventName,
|
|
77
|
+
listener: Listener<Events[EventName]>
|
|
78
|
+
): this {
|
|
79
|
+
for (const interceptor of this.interceptors) {
|
|
80
|
+
interceptor.off(event, listener)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return this
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public removeAllListeners<EventName extends ExtractEventNames<Events>>(
|
|
87
|
+
event?: EventName | undefined
|
|
88
|
+
): this {
|
|
89
|
+
for (const interceptors of this.interceptors) {
|
|
90
|
+
interceptors.removeAllListeners(event)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this
|
|
60
94
|
}
|
|
61
95
|
}
|
package/src/Interceptor.test.ts
CHANGED
|
@@ -18,6 +18,52 @@ it('does not set a maximum listeners limit', () => {
|
|
|
18
18
|
expect(interceptor['emitter'].getMaxListeners()).toBe(0)
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
+
describe('on()', () => {
|
|
22
|
+
it('adds a new listener using "on()"', () => {
|
|
23
|
+
const interceptor = new Interceptor(symbol)
|
|
24
|
+
expect(interceptor['emitter'].listenerCount('event')).toBe(0)
|
|
25
|
+
|
|
26
|
+
const listener = vi.fn()
|
|
27
|
+
interceptor.on('event', listener)
|
|
28
|
+
expect(interceptor['emitter'].listenerCount('event')).toBe(1)
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('once()', () => {
|
|
33
|
+
it('calls the listener only once', () => {
|
|
34
|
+
const interceptor = new Interceptor(symbol)
|
|
35
|
+
const listener = vi.fn()
|
|
36
|
+
|
|
37
|
+
interceptor.once('foo', listener)
|
|
38
|
+
expect(listener).not.toHaveBeenCalled()
|
|
39
|
+
|
|
40
|
+
interceptor['emitter'].emit('foo', 'bar')
|
|
41
|
+
|
|
42
|
+
expect(listener).toHaveBeenCalledTimes(1)
|
|
43
|
+
expect(listener).toHaveBeenCalledWith('bar')
|
|
44
|
+
|
|
45
|
+
listener.mockReset()
|
|
46
|
+
|
|
47
|
+
interceptor['emitter'].emit('foo', 'baz')
|
|
48
|
+
interceptor['emitter'].emit('foo', 'xyz')
|
|
49
|
+
expect(listener).toHaveBeenCalledTimes(0)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe('off()', () => {
|
|
54
|
+
it('removes a listener using "off()"', () => {
|
|
55
|
+
const interceptor = new Interceptor(symbol)
|
|
56
|
+
expect(interceptor['emitter'].listenerCount('event')).toBe(0)
|
|
57
|
+
|
|
58
|
+
const listener = vi.fn()
|
|
59
|
+
interceptor.on('event', listener)
|
|
60
|
+
expect(interceptor['emitter'].listenerCount('event')).toBe(1)
|
|
61
|
+
|
|
62
|
+
interceptor.off('event', listener)
|
|
63
|
+
expect(interceptor['emitter'].listenerCount('event')).toBe(0)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
21
67
|
describe('persistence', () => {
|
|
22
68
|
it('stores global reference to the applied interceptor', () => {
|
|
23
69
|
const interceptor = new Interceptor(symbol)
|
package/src/Interceptor.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Logger } from '@open-draft/logger'
|
|
2
|
-
import { Listener } from 'strict-event-emitter'
|
|
3
|
-
import { AsyncEventEmitter } from './utils/AsyncEventEmitter'
|
|
2
|
+
import { Emitter, EventMap, Listener } from 'strict-event-emitter'
|
|
4
3
|
|
|
5
4
|
export type InterceptorEventMap = Record<string, any>
|
|
6
5
|
export type InterceptorSubscription = () => void
|
|
@@ -34,7 +33,7 @@ export type ExtractEventNames<Events extends Record<string, any>> =
|
|
|
34
33
|
Events extends Record<infer EventName, any> ? EventName : never
|
|
35
34
|
|
|
36
35
|
export class Interceptor<Events extends InterceptorEventMap> {
|
|
37
|
-
protected emitter:
|
|
36
|
+
protected emitter: Emitter<Events>
|
|
38
37
|
protected subscriptions: Array<InterceptorSubscription>
|
|
39
38
|
protected logger: Logger
|
|
40
39
|
|
|
@@ -43,7 +42,7 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
43
42
|
constructor(private readonly symbol: symbol) {
|
|
44
43
|
this.readyState = InterceptorReadyState.INACTIVE
|
|
45
44
|
|
|
46
|
-
this.emitter = new
|
|
45
|
+
this.emitter = new Emitter()
|
|
47
46
|
this.subscriptions = []
|
|
48
47
|
this.logger = new Logger(symbol.description!)
|
|
49
48
|
|
|
@@ -84,12 +83,6 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
84
83
|
|
|
85
84
|
this.readyState = InterceptorReadyState.APPLYING
|
|
86
85
|
|
|
87
|
-
// Always activate the emitter when applying the interceptor.
|
|
88
|
-
// This will ensure the interceptor can process events after it's
|
|
89
|
-
// been disposed and re-applied again (it may be a singleton).
|
|
90
|
-
this.emitter.activate()
|
|
91
|
-
logger.info('activated the emiter!', this.emitter.readyState)
|
|
92
|
-
|
|
93
86
|
// Whenever applying a new interceptor, check if it hasn't been applied already.
|
|
94
87
|
// This enables to apply the same interceptor multiple times, for example from a different
|
|
95
88
|
// interceptor, only proxying events but keeping the stubs in a single place.
|
|
@@ -112,6 +105,8 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
112
105
|
runningInstance.emitter.removeListener(event, listener)
|
|
113
106
|
logger.info('removed proxied "%s" listener!', event)
|
|
114
107
|
})
|
|
108
|
+
|
|
109
|
+
return this
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
this.readyState = InterceptorReadyState.APPLIED
|
|
@@ -141,9 +136,9 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
141
136
|
* Listen to the interceptor's public events.
|
|
142
137
|
*/
|
|
143
138
|
public on<EventName extends ExtractEventNames<Events>>(
|
|
144
|
-
|
|
139
|
+
event: EventName,
|
|
145
140
|
listener: Listener<Events[EventName]>
|
|
146
|
-
):
|
|
141
|
+
): this {
|
|
147
142
|
const logger = this.logger.extend('on')
|
|
148
143
|
|
|
149
144
|
if (
|
|
@@ -151,12 +146,36 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
151
146
|
this.readyState === InterceptorReadyState.DISPOSED
|
|
152
147
|
) {
|
|
153
148
|
logger.info('cannot listen to events, already disposed!')
|
|
154
|
-
return
|
|
149
|
+
return this
|
|
155
150
|
}
|
|
156
151
|
|
|
157
|
-
logger.info('adding "%s" event listener:',
|
|
152
|
+
logger.info('adding "%s" event listener:', event, listener.name)
|
|
153
|
+
|
|
154
|
+
this.emitter.on(event, listener)
|
|
155
|
+
return this
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public once<EventName extends ExtractEventNames<Events>>(
|
|
159
|
+
event: EventName,
|
|
160
|
+
listener: Listener<Events[EventName]>
|
|
161
|
+
): this {
|
|
162
|
+
this.emitter.once(event, listener)
|
|
163
|
+
return this
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public off<EventName extends ExtractEventNames<Events>>(
|
|
167
|
+
event: EventName,
|
|
168
|
+
listener: Listener<Events[EventName]>
|
|
169
|
+
): this {
|
|
170
|
+
this.emitter.off(event, listener)
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
158
173
|
|
|
159
|
-
|
|
174
|
+
public removeAllListeners<EventName extends ExtractEventNames<Events>>(
|
|
175
|
+
event?: EventName
|
|
176
|
+
): this {
|
|
177
|
+
this.emitter.removeAllListeners(event)
|
|
178
|
+
return this
|
|
160
179
|
}
|
|
161
180
|
|
|
162
181
|
/**
|
|
@@ -196,7 +215,7 @@ export class Interceptor<Events extends InterceptorEventMap> {
|
|
|
196
215
|
logger.info('disposed of all subscriptions!', this.subscriptions.length)
|
|
197
216
|
}
|
|
198
217
|
|
|
199
|
-
this.emitter.
|
|
218
|
+
this.emitter.removeAllListeners()
|
|
200
219
|
logger.info('destroyed the listener!')
|
|
201
220
|
|
|
202
221
|
this.readyState = InterceptorReadyState.DISPOSED
|
|
@@ -5,6 +5,7 @@ import { BatchInterceptor } from './BatchInterceptor'
|
|
|
5
5
|
import { ClientRequestInterceptor } from './interceptors/ClientRequest'
|
|
6
6
|
import { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest'
|
|
7
7
|
import { toInteractiveRequest } from './utils/toInteractiveRequest'
|
|
8
|
+
import { emitAsync } from './utils/emitAsync'
|
|
8
9
|
|
|
9
10
|
export interface SerializedRequest {
|
|
10
11
|
id: string
|
|
@@ -166,20 +167,21 @@ export class RemoteHttpResolver extends Interceptor<HttpRequestEventMap> {
|
|
|
166
167
|
body: requestJson.body,
|
|
167
168
|
})
|
|
168
169
|
|
|
169
|
-
const interactiveRequest =
|
|
170
|
+
const { interactiveRequest, requestController } =
|
|
171
|
+
toInteractiveRequest(capturedRequest)
|
|
170
172
|
|
|
171
|
-
this.emitter.
|
|
173
|
+
this.emitter.once('request', () => {
|
|
174
|
+
if (requestController.responsePromise.state === 'pending') {
|
|
175
|
+
requestController.respondWith(undefined)
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
await emitAsync(this.emitter, 'request', {
|
|
172
180
|
request: interactiveRequest,
|
|
173
181
|
requestId: requestJson.id,
|
|
174
182
|
})
|
|
175
183
|
|
|
176
|
-
await
|
|
177
|
-
'request',
|
|
178
|
-
({ args: [{ requestId: pendingRequestId }] }) => {
|
|
179
|
-
return pendingRequestId === requestJson.id
|
|
180
|
-
}
|
|
181
|
-
)
|
|
182
|
-
const [mockedResponse] = await interactiveRequest.respondWith.invoked()
|
|
184
|
+
const mockedResponse = await requestController.responsePromise
|
|
183
185
|
|
|
184
186
|
if (!mockedResponse) {
|
|
185
187
|
return
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { vi, it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
2
|
import express from 'express'
|
|
3
3
|
import { IncomingMessage } from 'http'
|
|
4
|
+
import { Emitter } from 'strict-event-emitter'
|
|
4
5
|
import { Logger } from '@open-draft/logger'
|
|
5
6
|
import { HttpServer } from '@open-draft/test-server/http'
|
|
6
7
|
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
7
8
|
import { NodeClientRequest } from './NodeClientRequest'
|
|
8
9
|
import { getIncomingMessageBody } from './utils/getIncomingMessageBody'
|
|
9
10
|
import { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs'
|
|
10
|
-
import { AsyncEventEmitter } from '../../utils/AsyncEventEmitter'
|
|
11
11
|
import { sleep } from '../../../test/helpers'
|
|
12
12
|
import { HttpRequestEventMap } from '../../glossary'
|
|
13
13
|
|
|
@@ -37,7 +37,7 @@ afterAll(async () => {
|
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
it('gracefully finishes the request when it has a mocked response', async () => {
|
|
40
|
-
const emitter = new
|
|
40
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
41
41
|
const request = new NodeClientRequest(
|
|
42
42
|
normalizeClientRequestArgs('http:', 'http://any.thing', {
|
|
43
43
|
method: 'PUT',
|
|
@@ -88,7 +88,7 @@ it('gracefully finishes the request when it has a mocked response', async () =>
|
|
|
88
88
|
})
|
|
89
89
|
|
|
90
90
|
it('responds with a mocked response when requesting an existing hostname', async () => {
|
|
91
|
-
const emitter = new
|
|
91
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
92
92
|
const request = new NodeClientRequest(
|
|
93
93
|
normalizeClientRequestArgs('http:', httpServer.http.url('/comment')),
|
|
94
94
|
{
|
|
@@ -116,7 +116,7 @@ it('responds with a mocked response when requesting an existing hostname', async
|
|
|
116
116
|
})
|
|
117
117
|
|
|
118
118
|
it('performs the request as-is given resolver returned no mocked response', async () => {
|
|
119
|
-
const emitter = new
|
|
119
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
120
120
|
const request = new NodeClientRequest(
|
|
121
121
|
normalizeClientRequestArgs('http:', httpServer.http.url('/comment'), {
|
|
122
122
|
method: 'POST',
|
|
@@ -147,7 +147,7 @@ it('performs the request as-is given resolver returned no mocked response', asyn
|
|
|
147
147
|
})
|
|
148
148
|
|
|
149
149
|
it('emits the ENOTFOUND error connecting to a non-existing hostname given no mocked response', async () => {
|
|
150
|
-
const emitter = new
|
|
150
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
151
151
|
const request = new NodeClientRequest(
|
|
152
152
|
normalizeClientRequestArgs('http:', 'http://non-existing-url.com'),
|
|
153
153
|
{ emitter, logger }
|
|
@@ -165,7 +165,7 @@ it('emits the ENOTFOUND error connecting to a non-existing hostname given no moc
|
|
|
165
165
|
})
|
|
166
166
|
|
|
167
167
|
it('emits the ECONNREFUSED error connecting to an inactive server given no mocked response', async () => {
|
|
168
|
-
const emitter = new
|
|
168
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
169
169
|
const request = new NodeClientRequest(
|
|
170
170
|
normalizeClientRequestArgs('http:', 'http://127.0.0.1:12345'),
|
|
171
171
|
{
|
|
@@ -191,7 +191,7 @@ it('emits the ECONNREFUSED error connecting to an inactive server given no mocke
|
|
|
191
191
|
})
|
|
192
192
|
|
|
193
193
|
it('does not emit ENOTFOUND error connecting to an inactive server given mocked response', async () => {
|
|
194
|
-
const emitter = new
|
|
194
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
195
195
|
const handleError = vi.fn()
|
|
196
196
|
const request = new NodeClientRequest(
|
|
197
197
|
normalizeClientRequestArgs('http:', 'http://non-existing-url.com'),
|
|
@@ -221,7 +221,7 @@ it('does not emit ENOTFOUND error connecting to an inactive server given mocked
|
|
|
221
221
|
})
|
|
222
222
|
|
|
223
223
|
it('does not emit ECONNREFUSED error connecting to an inactive server given mocked response', async () => {
|
|
224
|
-
const emitter = new
|
|
224
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
225
225
|
const handleError = vi.fn()
|
|
226
226
|
const request = new NodeClientRequest(
|
|
227
227
|
normalizeClientRequestArgs('http:', 'http://localhost:9876'),
|
|
@@ -253,7 +253,7 @@ it('does not emit ECONNREFUSED error connecting to an inactive server given mock
|
|
|
253
253
|
})
|
|
254
254
|
|
|
255
255
|
it('sends the request body to the server given no mocked response', async () => {
|
|
256
|
-
const emitter = new
|
|
256
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
257
257
|
const request = new NodeClientRequest(
|
|
258
258
|
normalizeClientRequestArgs('http:', httpServer.http.url('/write'), {
|
|
259
259
|
method: 'POST',
|
|
@@ -284,7 +284,7 @@ it('sends the request body to the server given no mocked response', async () =>
|
|
|
284
284
|
})
|
|
285
285
|
|
|
286
286
|
it('does not send request body to the original server given mocked response', async () => {
|
|
287
|
-
const emitter = new
|
|
287
|
+
const emitter = new Emitter<HttpRequestEventMap>()
|
|
288
288
|
const request = new NodeClientRequest(
|
|
289
289
|
normalizeClientRequestArgs('http:', httpServer.http.url('/write'), {
|
|
290
290
|
method: 'POST',
|