@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.
Files changed (85) hide show
  1. package/lib/browser/Interceptor-8d5fd4c6.d.ts +86 -0
  2. package/lib/browser/{chunk-ANLPTCZ5.mjs → chunk-AN3YI76R.mjs} +33 -26
  3. package/lib/browser/{chunk-4CFMDU7Z.js → chunk-CWVY2E3W.js} +20 -134
  4. package/lib/browser/{chunk-OSIUQA4X.js → chunk-FFBQOFWV.js} +38 -31
  5. package/lib/browser/{chunk-VMXB5F2J.mjs → chunk-HXJPKJY3.mjs} +25 -15
  6. package/lib/browser/{chunk-DBFLI5DJ.js → chunk-KITNLK66.js} +30 -20
  7. package/lib/browser/chunk-KK6APRON.mjs +58 -0
  8. package/lib/browser/{chunk-GXJLJMOT.mjs → chunk-QPMXOLDO.mjs} +21 -135
  9. package/lib/browser/chunk-X3NRJIZW.js +58 -0
  10. package/lib/browser/index.d.ts +7 -3
  11. package/lib/browser/index.js +24 -5
  12. package/lib/browser/index.mjs +22 -3
  13. package/lib/browser/interceptors/XMLHttpRequest/index.d.ts +4 -3
  14. package/lib/browser/interceptors/XMLHttpRequest/index.js +4 -4
  15. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +3 -3
  16. package/lib/browser/interceptors/fetch/index.d.ts +2 -1
  17. package/lib/browser/interceptors/fetch/index.js +4 -4
  18. package/lib/browser/interceptors/fetch/index.mjs +3 -3
  19. package/lib/browser/presets/browser.d.ts +2 -1
  20. package/lib/browser/presets/browser.js +6 -6
  21. package/lib/browser/presets/browser.mjs +4 -4
  22. package/lib/node/{BatchInterceptor-c841b068.d.ts → BatchInterceptor-9785c567.d.ts} +5 -2
  23. package/lib/node/Interceptor-7a701c1f.d.ts +86 -0
  24. package/lib/node/RemoteHttpInterceptor.d.ts +3 -2
  25. package/lib/node/RemoteHttpInterceptor.js +19 -18
  26. package/lib/node/RemoteHttpInterceptor.mjs +15 -14
  27. package/lib/node/chunk-3IYIKC3X.mjs +6 -0
  28. package/lib/node/{chunk-XYZRP5S2.js → chunk-3XFLRXRY.js} +20 -134
  29. package/lib/node/chunk-5PTPJLB7.js +58 -0
  30. package/lib/node/{chunk-HSCXCLVT.mjs → chunk-FB53TMYN.mjs} +33 -26
  31. package/lib/node/{chunk-RGYCLCLK.mjs → chunk-GM3YBSM3.mjs} +21 -135
  32. package/lib/node/{chunk-E6YC337Q.js → chunk-JCWVLTP7.js} +35 -28
  33. package/lib/node/{chunk-OL7OR4RL.mjs → chunk-MCO3RLQC.mjs} +48 -26
  34. package/lib/node/{chunk-3MYUI4B2.js → chunk-NCHFM2TB.js} +50 -28
  35. package/lib/node/chunk-OGN3ZR35.js +6 -0
  36. package/lib/node/{chunk-VS3GJPUE.mjs → chunk-UBEFEZXT.mjs} +22 -3
  37. package/lib/node/{chunk-MVPEJK4V.js → chunk-UF7QIAQ5.js} +23 -4
  38. package/lib/node/chunk-YQGTMMOZ.mjs +58 -0
  39. package/lib/node/index.d.ts +3 -2
  40. package/lib/node/index.js +3 -3
  41. package/lib/node/index.mjs +2 -2
  42. package/lib/node/interceptors/ClientRequest/index.d.ts +4 -3
  43. package/lib/node/interceptors/ClientRequest/index.js +5 -4
  44. package/lib/node/interceptors/ClientRequest/index.mjs +4 -3
  45. package/lib/node/interceptors/XMLHttpRequest/index.d.ts +4 -3
  46. package/lib/node/interceptors/XMLHttpRequest/index.js +5 -4
  47. package/lib/node/interceptors/XMLHttpRequest/index.mjs +4 -3
  48. package/lib/node/interceptors/fetch/index.d.ts +2 -1
  49. package/lib/node/interceptors/fetch/index.js +27 -17
  50. package/lib/node/interceptors/fetch/index.mjs +25 -15
  51. package/lib/node/presets/node.d.ts +3 -2
  52. package/lib/node/presets/node.js +7 -6
  53. package/lib/node/presets/node.mjs +5 -4
  54. package/package.json +2 -2
  55. package/src/BatchInterceptor.test.ts +141 -0
  56. package/src/BatchInterceptor.ts +38 -4
  57. package/src/Interceptor.test.ts +46 -0
  58. package/src/Interceptor.ts +35 -16
  59. package/src/RemoteHttpInterceptor.ts +11 -9
  60. package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +10 -10
  61. package/src/interceptors/ClientRequest/NodeClientRequest.ts +80 -43
  62. package/src/interceptors/ClientRequest/http.get.ts +3 -1
  63. package/src/interceptors/ClientRequest/http.request.ts +3 -1
  64. package/src/interceptors/ClientRequest/index.test.ts +2 -3
  65. package/src/interceptors/ClientRequest/index.ts +2 -2
  66. package/src/interceptors/ClientRequest/utils/createRequest.test.ts +2 -2
  67. package/src/interceptors/ClientRequest/utils/createResponse.test.ts +23 -0
  68. package/src/interceptors/ClientRequest/utils/createResponse.ts +18 -13
  69. package/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +29 -25
  70. package/src/interceptors/XMLHttpRequest/index.ts +2 -2
  71. package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +4 -2
  72. package/src/interceptors/fetch/index.ts +26 -13
  73. package/src/utils/RequestController.ts +21 -0
  74. package/src/utils/emitAsync.ts +25 -0
  75. package/src/utils/responseUtils.ts +5 -0
  76. package/src/utils/toInteractiveRequest.ts +17 -23
  77. package/lib/browser/Interceptor-0a020bc4.d.ts +0 -116
  78. package/lib/browser/chunk-PCFJD76X.js +0 -64
  79. package/lib/browser/chunk-RT3ATOJH.mjs +0 -64
  80. package/lib/node/Interceptor-738f79c5.d.ts +0 -116
  81. package/lib/node/chunk-STA6QBYM.mjs +0 -64
  82. package/lib/node/chunk-ZJOF5MEZ.js +0 -64
  83. package/src/utils/AsyncEventEmitter.test.ts +0 -102
  84. package/src/utils/AsyncEventEmitter.ts +0 -193
  85. package/src/utils/createLazyCallback.ts +0 -49
@@ -1,18 +1,19 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunk3MYUI4B2js = require('../chunk-3MYUI4B2.js');
3
+ var _chunkNCHFM2TBjs = require('../chunk-NCHFM2TB.js');
4
4
 
5
5
 
6
- var _chunkE6YC337Qjs = require('../chunk-E6YC337Q.js');
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-ZJOF5MEZ.js');
10
- require('../chunk-XYZRP5S2.js');
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, _chunk3MYUI4B2js.ClientRequestInterceptor)(),
15
- new (0, _chunkE6YC337Qjs.XMLHttpRequestInterceptor)()
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-OL7OR4RL.mjs";
3
+ } from "../chunk-MCO3RLQC.mjs";
4
4
  import {
5
5
  XMLHttpRequestInterceptor
6
- } from "../chunk-HSCXCLVT.mjs";
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-STA6QBYM.mjs";
10
- import "../chunk-RGYCLCLK.mjs";
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.1",
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.0"
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
+ })
@@ -1,5 +1,5 @@
1
1
  import { EventMap, Listener } from 'strict-event-emitter'
2
- import { ExtractEventNames, Interceptor } from './Interceptor'
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.forEach((interceptor) => {
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
  }
@@ -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)
@@ -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: AsyncEventEmitter<Events>
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 AsyncEventEmitter()
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
- eventName: EventName,
139
+ event: EventName,
145
140
  listener: Listener<Events[EventName]>
146
- ): void {
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:', eventName, listener.name)
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
- this.emitter.on(eventName, listener)
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.deactivate()
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 = toInteractiveRequest(capturedRequest)
170
+ const { interactiveRequest, requestController } =
171
+ toInteractiveRequest(capturedRequest)
170
172
 
171
- this.emitter.emit('request', {
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 this.emitter.untilIdle(
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
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 AsyncEventEmitter<HttpRequestEventMap>()
287
+ const emitter = new Emitter<HttpRequestEventMap>()
288
288
  const request = new NodeClientRequest(
289
289
  normalizeClientRequestArgs('http:', httpServer.http.url('/write'), {
290
290
  method: 'POST',