@mswjs/interceptors 0.15.3 → 0.16.0

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 (91) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +68 -49
  3. package/lib/BatchInterceptor.d.ts +18 -0
  4. package/lib/BatchInterceptor.js +79 -0
  5. package/lib/BatchInterceptor.js.map +1 -0
  6. package/lib/Interceptor.d.ts +49 -0
  7. package/lib/Interceptor.js +197 -0
  8. package/lib/Interceptor.js.map +1 -0
  9. package/lib/RemoteInterceptor.d.ts +24 -0
  10. package/lib/RemoteInterceptor.js +216 -0
  11. package/lib/RemoteInterceptor.js.map +1 -0
  12. package/lib/glossary.d.ts +32 -0
  13. package/lib/glossary.js +3 -0
  14. package/lib/glossary.js.map +1 -0
  15. package/lib/index.d.ts +2 -2
  16. package/lib/index.js +2 -2
  17. package/lib/index.js.map +1 -1
  18. package/lib/interceptors/ClientRequest/NodeClientRequest.d.ts +5 -5
  19. package/lib/interceptors/ClientRequest/NodeClientRequest.js +56 -15
  20. package/lib/interceptors/ClientRequest/NodeClientRequest.js.map +1 -1
  21. package/lib/interceptors/ClientRequest/http.get.d.ts +2 -3
  22. package/lib/interceptors/ClientRequest/http.get.js +2 -5
  23. package/lib/interceptors/ClientRequest/http.get.js.map +1 -1
  24. package/lib/interceptors/ClientRequest/http.request.d.ts +2 -3
  25. package/lib/interceptors/ClientRequest/http.request.js +3 -6
  26. package/lib/interceptors/ClientRequest/http.request.js.map +1 -1
  27. package/lib/interceptors/ClientRequest/index.d.ts +14 -4
  28. package/lib/interceptors/ClientRequest/index.js +59 -46
  29. package/lib/interceptors/ClientRequest/index.js.map +1 -1
  30. package/lib/interceptors/ClientRequest/utils/getIncomingMessageBody.js +7 -2
  31. package/lib/interceptors/ClientRequest/utils/getIncomingMessageBody.js.map +1 -1
  32. package/lib/interceptors/XMLHttpRequest/XMLHttpRequestOverride.d.ts +11 -4
  33. package/lib/interceptors/XMLHttpRequest/XMLHttpRequestOverride.js +110 -58
  34. package/lib/interceptors/XMLHttpRequest/XMLHttpRequestOverride.js.map +1 -1
  35. package/lib/interceptors/XMLHttpRequest/index.d.ts +11 -5
  36. package/lib/interceptors/XMLHttpRequest/index.js +43 -25
  37. package/lib/interceptors/XMLHttpRequest/index.js.map +1 -1
  38. package/lib/interceptors/fetch/index.d.ts +8 -2
  39. package/lib/interceptors/fetch/index.js +120 -68
  40. package/lib/interceptors/fetch/index.js.map +1 -1
  41. package/lib/presets/browser.d.ts +3 -1
  42. package/lib/presets/browser.js +2 -2
  43. package/lib/presets/browser.js.map +1 -1
  44. package/lib/presets/node.d.ts +3 -1
  45. package/lib/presets/node.js +1 -1
  46. package/lib/presets/node.js.map +1 -1
  47. package/lib/utils/AsyncEventEmitter.d.ts +29 -0
  48. package/lib/utils/AsyncEventEmitter.js +241 -0
  49. package/lib/utils/AsyncEventEmitter.js.map +1 -0
  50. package/lib/utils/createLazyCallback.d.ts +11 -0
  51. package/lib/utils/createLazyCallback.js +75 -0
  52. package/lib/utils/createLazyCallback.js.map +1 -0
  53. package/lib/utils/nextTick.d.ts +2 -0
  54. package/lib/utils/nextTick.js +16 -0
  55. package/lib/utils/nextTick.js.map +1 -0
  56. package/lib/utils/toIsoResponse.d.ts +1 -1
  57. package/package.json +6 -6
  58. package/src/BatchInterceptor.test.ts +113 -0
  59. package/src/BatchInterceptor.ts +60 -0
  60. package/src/Interceptor.test.ts +166 -0
  61. package/src/Interceptor.ts +226 -0
  62. package/src/RemoteInterceptor.ts +176 -0
  63. package/src/glossary.ts +42 -0
  64. package/src/index.ts +2 -2
  65. package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +87 -70
  66. package/src/interceptors/ClientRequest/NodeClientRequest.ts +139 -100
  67. package/src/interceptors/ClientRequest/http.get.ts +7 -11
  68. package/src/interceptors/ClientRequest/http.request.ts +8 -12
  69. package/src/interceptors/ClientRequest/index.test.ts +43 -0
  70. package/src/interceptors/ClientRequest/index.ts +46 -46
  71. package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +9 -0
  72. package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts +9 -2
  73. package/src/interceptors/XMLHttpRequest/XMLHttpRequestOverride.ts +215 -159
  74. package/src/interceptors/XMLHttpRequest/index.ts +41 -23
  75. package/src/interceptors/fetch/index.ts +81 -55
  76. package/src/presets/browser.ts +3 -3
  77. package/src/presets/node.ts +3 -3
  78. package/src/utils/AsyncEventEmitter.test.ts +68 -0
  79. package/src/utils/AsyncEventEmitter.ts +171 -0
  80. package/src/utils/createLazyCallback.ts +49 -0
  81. package/src/utils/nextTick.ts +11 -0
  82. package/src/utils/toIsoResponse.ts +1 -1
  83. package/lib/createInterceptor.d.ts +0 -54
  84. package/lib/createInterceptor.js +0 -27
  85. package/lib/createInterceptor.js.map +0 -1
  86. package/lib/remote.d.ts +0 -21
  87. package/lib/remote.js +0 -178
  88. package/lib/remote.js.map +0 -1
  89. package/src/createInterceptor.ts +0 -100
  90. package/src/remote.ts +0 -174
  91. package/src/utils/.DS_Store +0 -0
@@ -1,79 +1,105 @@
1
1
  import {
2
2
  Headers,
3
- headersToObject,
4
- objectToHeaders,
5
3
  flattenHeadersObject,
4
+ objectToHeaders,
5
+ headersToObject,
6
6
  } from 'headers-polyfill'
7
- import {
8
- Interceptor,
9
- IsomorphicRequest,
7
+ import type {
8
+ HttpRequestEventMap,
9
+ InteractiveIsomorphicRequest,
10
10
  IsomorphicResponse,
11
- } from '../../createInterceptor'
11
+ } from '../../glossary'
12
+ import { Interceptor } from '../../Interceptor'
13
+ import { createLazyCallback } from '../../utils/createLazyCallback'
12
14
  import { toIsoResponse } from '../../utils/toIsoResponse'
13
15
  import { uuidv4 } from '../../utils/uuid'
14
16
 
15
- const debug = require('debug')('fetch')
17
+ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
18
+ static symbol = Symbol('fetch')
16
19
 
17
- export const interceptFetch: Interceptor = (observer, resolver) => {
18
- const pureFetch = window.fetch
20
+ constructor() {
21
+ super(FetchInterceptor.symbol)
22
+ }
19
23
 
20
- debug('replacing "window.fetch"...')
24
+ protected checkEnvironment() {
25
+ return (
26
+ typeof globalThis !== 'undefined' &&
27
+ typeof globalThis.fetch !== 'undefined'
28
+ )
29
+ }
21
30
 
22
- window.fetch = async (input, init) => {
23
- const request = new Request(input, init)
24
- const url = typeof input === 'string' ? input : input.url
25
- const method = request.method
31
+ protected setup() {
32
+ const pureFetch = globalThis.fetch
26
33
 
27
- debug('[%s] %s', method, url)
34
+ globalThis.fetch = async (input, init) => {
35
+ const request = new Request(input, init)
36
+ const url = typeof input === 'string' ? input : input.url
37
+ const method = request.method
28
38
 
29
- const isoRequest: IsomorphicRequest = {
30
- id: uuidv4(),
31
- url: new URL(url, location.origin),
32
- method: method,
33
- headers: new Headers(request.headers),
34
- credentials: request.credentials,
35
- body: await request.clone().text(),
36
- }
37
- debug('isomorphic request', isoRequest)
38
- observer.emit('request', isoRequest)
39
+ this.log('[%s] %s', method, url)
39
40
 
40
- debug('awaiting for the mocked response...')
41
- const response = await resolver(isoRequest, request)
42
- debug('mocked response', response)
41
+ const isomorphicRequest: InteractiveIsomorphicRequest = {
42
+ id: uuidv4(),
43
+ url: new URL(url, location.origin),
44
+ method: method,
45
+ headers: new Headers(request.headers),
46
+ credentials: request.credentials,
47
+ body: await request.clone().text(),
48
+ respondWith: createLazyCallback(),
49
+ }
43
50
 
44
- if (response) {
45
- const isomorphicResponse = toIsoResponse(response)
46
- debug('derived isomorphic response', isomorphicResponse)
51
+ this.log('isomorphic request', isomorphicRequest)
47
52
 
48
- observer.emit('response', isoRequest, isomorphicResponse)
53
+ this.log(
54
+ 'emitting the "request" event for %d listener(s)...',
55
+ this.emitter.listenerCount('request')
56
+ )
57
+ this.emitter.emit('request', isomorphicRequest)
49
58
 
50
- return new Response(response.body, {
51
- ...isomorphicResponse,
52
- // `Response.headers` cannot be instantiated with the `Headers` polyfill.
53
- // Apparently, it halts if the `Headers` class contains unknown properties
54
- // (i.e. the internal `Headers.map`).
55
- headers: flattenHeadersObject(response.headers || {}),
56
- })
57
- }
59
+ this.log('awaiting for the mocked response...')
58
60
 
59
- debug('no mocked response found, bypassing...')
61
+ await this.emitter.untilIdle('request')
62
+ this.log('all request listeners have been resolved!')
60
63
 
61
- return pureFetch(request).then(async (response) => {
62
- const cloneResponse = response.clone()
63
- debug('original fetch performed', cloneResponse)
64
+ const [mockedResponse] = await isomorphicRequest.respondWith.invoked()
65
+ this.log('event.respondWith called with:', mockedResponse)
64
66
 
65
- observer.emit(
66
- 'response',
67
- isoRequest,
68
- await normalizeFetchResponse(cloneResponse)
69
- )
70
- return response
71
- })
72
- }
67
+ if (mockedResponse) {
68
+ this.log('received mocked response:', mockedResponse)
69
+
70
+ const isomorphicResponse = toIsoResponse(mockedResponse)
71
+ this.log('derived isomorphic response:', isomorphicResponse)
72
+
73
+ this.emitter.emit('response', isomorphicRequest, isomorphicResponse)
74
+
75
+ return new Response(mockedResponse.body, {
76
+ ...isomorphicResponse,
77
+ // `Response.headers` cannot be instantiated with the `Headers` polyfill.
78
+ // Apparently, it halts if the `Headers` class contains unknown properties
79
+ // (i.e. the internal `Headers.map`).
80
+ headers: flattenHeadersObject(mockedResponse.headers || {}),
81
+ })
82
+ }
83
+
84
+ this.log('no mocked response received!')
73
85
 
74
- return () => {
75
- debug('restoring modules...')
76
- window.fetch = pureFetch
86
+ return pureFetch(request).then(async (response) => {
87
+ const cloneResponse = response.clone()
88
+ this.log('original fetch performed', cloneResponse)
89
+
90
+ this.emitter.emit(
91
+ 'response',
92
+ isomorphicRequest,
93
+ await normalizeFetchResponse(cloneResponse)
94
+ )
95
+ return response
96
+ })
97
+ }
98
+
99
+ this.subscriptions.push(() => {
100
+ globalThis.fetch = pureFetch
101
+ this.log('restored native "globalThis.fetch"!', globalThis.fetch.name)
102
+ })
77
103
  }
78
104
  }
79
105
 
@@ -1,8 +1,8 @@
1
- import { interceptXMLHttpRequest } from '../interceptors/XMLHttpRequest'
2
- import { interceptFetch } from '../interceptors/fetch'
1
+ import { FetchInterceptor } from '../interceptors/fetch'
2
+ import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'
3
3
 
4
4
  /**
5
5
  * The default preset provisions the interception of requests
6
6
  * regardless of their type (fetch/XMLHttpRequest).
7
7
  */
8
- export default [interceptXMLHttpRequest, interceptFetch]
8
+ export default [new FetchInterceptor(), new XMLHttpRequestInterceptor()]
@@ -1,8 +1,8 @@
1
- import { interceptClientRequest } from '../interceptors/ClientRequest'
2
- import { interceptXMLHttpRequest } from '../interceptors/XMLHttpRequest'
1
+ import { ClientRequestInterceptor } from '../interceptors/ClientRequest'
2
+ import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'
3
3
 
4
4
  /**
5
5
  * The default preset provisions the interception of requests
6
6
  * regardless of their type (http/https/XMLHttpRequest).
7
7
  */
8
- export default [interceptClientRequest, interceptXMLHttpRequest]
8
+ export default [new ClientRequestInterceptor(), new XMLHttpRequestInterceptor()]
@@ -0,0 +1,68 @@
1
+ import { AsyncEventEmitter } from './AsyncEventEmitter'
2
+ import { sleep } from '../../test/helpers'
3
+
4
+ it('emits and listens to events', () => {
5
+ const emitter = new AsyncEventEmitter<{ hello(name: string): void }>()
6
+ const listener = jest.fn()
7
+ emitter.on('hello', listener)
8
+ emitter.emit('hello', 'John')
9
+
10
+ expect(listener).toHaveBeenCalledTimes(1)
11
+ expect(listener).toHaveBeenCalledWith('John')
12
+ })
13
+
14
+ it('resolves "untilIdle" when all the event listeners are done', async () => {
15
+ const emitter = new AsyncEventEmitter<{ speak(word: string): void }>()
16
+
17
+ const results: string[] = []
18
+ const firstListener = jest.fn(() => results.push('first'))
19
+ emitter.on('speak', firstListener)
20
+
21
+ const secondListener = jest.fn(async () => {
22
+ await sleep(150)
23
+ results.push('second')
24
+ })
25
+ emitter.on('speak', secondListener)
26
+
27
+ emitter.emit('speak', 'hi')
28
+ await emitter.untilIdle('speak')
29
+
30
+ // All listeners must be called.
31
+ expect(firstListener).toHaveBeenCalledTimes(1)
32
+ expect(secondListener).toHaveBeenCalledTimes(1)
33
+
34
+ // All promise listeners must be awaited.
35
+ expect(results).toEqual(['first', 'second'])
36
+ })
37
+
38
+ it('resolves "untilIdle" immediately if there are no pending listeners', async () => {
39
+ const emitter = new AsyncEventEmitter<{ ping(): void }>()
40
+ emitter.emit('ping')
41
+
42
+ await expect(emitter.untilIdle('ping')).resolves.toBeUndefined()
43
+ })
44
+
45
+ it('propagates listener exceptions to "untilIdle" promise', async () => {
46
+ const emitter = new AsyncEventEmitter<{ ping(): void }>()
47
+
48
+ const error = new Error('oops')
49
+ const listener = jest.fn(() => {
50
+ throw error
51
+ })
52
+ emitter.on('ping', listener)
53
+
54
+ emitter.emit('ping')
55
+ await expect(emitter.untilIdle('ping')).rejects.toBe(error)
56
+ })
57
+
58
+ it('does not emit events once the emitter was deactivated', () => {
59
+ const emitter = new AsyncEventEmitter<{ ping(): void }>()
60
+
61
+ const listener = jest.fn()
62
+ emitter.on('ping', listener)
63
+ emitter.deactivate()
64
+
65
+ emitter.emit('ping')
66
+
67
+ expect(listener).not.toHaveBeenCalled()
68
+ })
@@ -0,0 +1,171 @@
1
+ import { Debugger, debug } from 'debug'
2
+ import { StrictEventEmitter, EventMapType } from 'strict-event-emitter'
3
+ import { nextTick } from './nextTick'
4
+
5
+ export type QueueItem = Promise<void>
6
+
7
+ export enum AsyncEventEmitterReadyState {
8
+ ACTIVE = 'ACTIVE',
9
+ DEACTIVATED = 'DEACTIVATED',
10
+ }
11
+
12
+ export class AsyncEventEmitter<
13
+ EventMap extends EventMapType
14
+ > extends StrictEventEmitter<EventMap> {
15
+ public readyState: AsyncEventEmitterReadyState
16
+
17
+ private log: Debugger
18
+ protected queue: Map<keyof EventMap, QueueItem[]>
19
+
20
+ constructor() {
21
+ super()
22
+
23
+ this.log = debug('async-event-emitter')
24
+ this.queue = new Map()
25
+
26
+ this.readyState = AsyncEventEmitterReadyState.ACTIVE
27
+ }
28
+
29
+ public on<Event extends keyof EventMap>(
30
+ event: Event,
31
+ listener: EventMap[Event]
32
+ ) {
33
+ const log = this.log.extend('on')
34
+
35
+ log('adding "%s" listener...', event)
36
+
37
+ if (this.readyState === AsyncEventEmitterReadyState.DEACTIVATED) {
38
+ log('the emitter is destroyed, skipping!')
39
+ return this
40
+ }
41
+
42
+ return super.on(event, (async (...args: unknown[]) => {
43
+ // Event queue is always established when calling ".emit()".
44
+ const queue = this.openListenerQueue(event)
45
+
46
+ log('awaiting the "%s" listener...', event)
47
+
48
+ // Whenever a listener is called, create a new Promise
49
+ // that resolves when that listener function completes its execution.
50
+ queue.push(
51
+ new Promise<void>(async (resolve, reject) => {
52
+ try {
53
+ // Treat listeners as potentially asynchronous functions
54
+ // so they could be awaited.
55
+ await listener(...args)
56
+ resolve()
57
+
58
+ log('"%s" listener has resolved!', event)
59
+ } catch (error) {
60
+ log('"%s" listener has rejected!', error)
61
+ reject(error)
62
+ }
63
+ })
64
+ )
65
+ }) as EventMap[Event])
66
+ }
67
+
68
+ public emit<Event extends keyof EventMap>(
69
+ event: Event,
70
+ ...args: Parameters<EventMap[Event]>
71
+ ): boolean {
72
+ const log = this.log.extend('emit')
73
+
74
+ log('emitting "%s" event...', event)
75
+
76
+ if (this.readyState === AsyncEventEmitterReadyState.DEACTIVATED) {
77
+ log('the emitter is destroyed, skipping!')
78
+ return false
79
+ }
80
+
81
+ // Establish the Promise queue for this particular event.
82
+ this.openListenerQueue(event)
83
+
84
+ log('appending a one-time cleanup "%s" listener...', event)
85
+
86
+ // Append a one-time clean up listener.
87
+ this.once(event, (() => {
88
+ // Clear the Promise queue for this particular event
89
+ // in the next tick so the Promise in "untilIdle" has
90
+ // time to properly resolve.
91
+ nextTick(() => {
92
+ this.queue.delete(event)
93
+ log('cleaned up "%s" listeners queue!', event)
94
+ })
95
+ }) as EventMap[Event])
96
+
97
+ return super.emit(event, ...args)
98
+ }
99
+
100
+ /**
101
+ * Returns a promise that resolves when all the listeners for the given event
102
+ * has been called. Awaits asynchronous listeners.
103
+ * If the event has no listeners, resolves immediately.
104
+ */
105
+ public async untilIdle<Event extends keyof EventMap>(
106
+ event: Event
107
+ ): Promise<void> {
108
+ const listenersQueue = this.queue.get(event) || []
109
+ await Promise.all(listenersQueue).finally(() => {
110
+ // Clear the queue one the promise settles
111
+ // so that different events don't share the same queue.
112
+ this.queue.delete(event)
113
+ })
114
+ }
115
+
116
+ private openListenerQueue<Event extends keyof EventMap>(
117
+ event: Event
118
+ ): QueueItem[] {
119
+ const log = this.log.extend('openListenerQueue')
120
+
121
+ log('opening "%s" listeners queue...', event)
122
+
123
+ const queue = this.queue.get(event)
124
+
125
+ if (!queue) {
126
+ log('no queue found, creating one...')
127
+
128
+ this.queue.set(event, [])
129
+ return []
130
+ }
131
+
132
+ log('returning an exising queue:', queue)
133
+ return queue
134
+ }
135
+
136
+ public removeAllListeners<Event extends keyof EventMap>(event?: Event) {
137
+ const log = this.log.extend('removeAllListeners')
138
+ log('event:', event)
139
+
140
+ if (event) {
141
+ this.queue.delete(event)
142
+ log('cleared the "%s" listeners queue!', event, this.queue.get(event))
143
+ } else {
144
+ this.queue.clear()
145
+ log('cleared the listeners queue!', this.queue)
146
+ }
147
+
148
+ return super.removeAllListeners(event)
149
+ }
150
+
151
+ public activate(): void {
152
+ const log = this.log.extend('activate')
153
+ this.readyState = AsyncEventEmitterReadyState.ACTIVE
154
+ log('set state to:', this.readyState)
155
+ }
156
+
157
+ /**
158
+ * Deactivate this event emitter.
159
+ * Deactivated emitter can no longer emit and listen to events
160
+ * and needs to be activated again in order to do so.
161
+ */
162
+ public deactivate(): void {
163
+ const log = this.log.extend('deactivate')
164
+
165
+ log('removing all listeners...')
166
+ this.removeAllListeners()
167
+
168
+ this.readyState = AsyncEventEmitterReadyState.DEACTIVATED
169
+ log('set state to:', this.readyState)
170
+ }
171
+ }
@@ -0,0 +1,49 @@
1
+ export type AnyFunction = (...args: any[]) => any
2
+
3
+ export type LazyCallbackReturnType<FnType extends AnyFunction> =
4
+ | Parameters<FnType>
5
+ | []
6
+
7
+ export interface LazyCallback<FnType extends AnyFunction> {
8
+ (...args: Parameters<FnType>): void
9
+ invoked(): Promise<LazyCallbackReturnType<FnType>>
10
+ }
11
+
12
+ export interface LazyCallbackOptions {
13
+ maxCalls?: number
14
+ maxCallsCallback?(): void
15
+ }
16
+
17
+ export function createLazyCallback<FnType extends AnyFunction>(
18
+ options: LazyCallbackOptions = {}
19
+ ): LazyCallback<FnType> {
20
+ let calledTimes = 0
21
+ let autoResolveTimeout: NodeJS.Timeout
22
+ let remoteResolve: (args: LazyCallbackReturnType<FnType>) => unknown
23
+
24
+ const callPromise = new Promise<LazyCallbackReturnType<FnType>>((resolve) => {
25
+ remoteResolve = resolve
26
+ }).finally(() => {
27
+ clearTimeout(autoResolveTimeout)
28
+ })
29
+
30
+ const fn: LazyCallback<FnType> = function (...args) {
31
+ if (options.maxCalls && calledTimes >= options.maxCalls) {
32
+ options.maxCallsCallback?.()
33
+ }
34
+
35
+ remoteResolve(args)
36
+ calledTimes++
37
+ }
38
+
39
+ fn.invoked = async () => {
40
+ // Immediately resolve the callback if it hasn't been called already.
41
+ autoResolveTimeout = setTimeout(() => {
42
+ remoteResolve([])
43
+ }, 0)
44
+
45
+ return callPromise
46
+ }
47
+
48
+ return fn
49
+ }
@@ -0,0 +1,11 @@
1
+ export function nextTick(callback: () => void) {
2
+ setTimeout(callback, 0)
3
+ }
4
+
5
+ export function nextTickAsync(callback: () => void) {
6
+ return new Promise((resolve) => {
7
+ setTimeout(() => {
8
+ resolve(callback())
9
+ }, 0)
10
+ })
11
+ }
@@ -1,5 +1,5 @@
1
1
  import { objectToHeaders } from 'headers-polyfill'
2
- import { IsomorphicResponse, MockedResponse } from '../createInterceptor'
2
+ import { IsomorphicResponse, MockedResponse } from '../glossary'
3
3
 
4
4
  /**
5
5
  * Converts a given mocked response object into an isomorphic response.
@@ -1,54 +0,0 @@
1
- /// <reference types="node" />
2
- import { IncomingMessage } from 'http';
3
- import { HeadersObject, Headers } from 'headers-polyfill';
4
- import { StrictEventEmitter } from 'strict-event-emitter';
5
- export declare type Interceptor = (observer: Observer, resolver: Resolver) => InterceptorCleanupFn;
6
- export declare type Observer = StrictEventEmitter<InterceptorEventsMap>;
7
- /**
8
- * A side-effect function to restore all the patched modules.
9
- */
10
- export declare type InterceptorCleanupFn = () => void;
11
- export declare type RequestCredentials = 'omit' | 'include' | 'same-origin';
12
- export interface IsomorphicRequest {
13
- id: string;
14
- url: URL;
15
- method: string;
16
- headers: Headers;
17
- /**
18
- * The value of the request client's "credentials" option
19
- * or a compatible alternative (i.e. `withCredentials` for `XMLHttpRequest`).
20
- * Always equals to "omit" in Node.js.
21
- */
22
- credentials: RequestCredentials;
23
- body?: string;
24
- }
25
- export interface IsomorphicResponse {
26
- status: number;
27
- statusText: string;
28
- headers: Headers;
29
- body?: string;
30
- }
31
- export interface MockedResponse extends Omit<Partial<IsomorphicResponse>, 'headers'> {
32
- headers?: HeadersObject;
33
- }
34
- export interface InterceptorEventsMap {
35
- request(request: IsomorphicRequest): void;
36
- response(request: IsomorphicRequest, response: IsomorphicResponse): void;
37
- }
38
- export declare type Resolver = (request: IsomorphicRequest, ref: IncomingMessage | XMLHttpRequest | Request) => MockedResponse | Promise<MockedResponse | void> | void;
39
- export interface InterceptorOptions {
40
- modules: Interceptor[];
41
- resolver: Resolver;
42
- }
43
- export interface InterceptorApi {
44
- /**
45
- * Apply necessary module patches to provision the interception of requests.
46
- */
47
- apply(): void;
48
- on<Event extends keyof InterceptorEventsMap>(event: Event, listener: InterceptorEventsMap[Event]): void;
49
- /**
50
- * Restore all applied module patches and disable the interception.
51
- */
52
- restore(): void;
53
- }
54
- export declare function createInterceptor(options: InterceptorOptions): InterceptorApi;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createInterceptor = void 0;
4
- var strict_event_emitter_1 = require("strict-event-emitter");
5
- function createInterceptor(options) {
6
- var observer = new strict_event_emitter_1.StrictEventEmitter();
7
- var cleanupFns = [];
8
- return {
9
- apply: function () {
10
- cleanupFns = options.modules.map(function (interceptor) {
11
- return interceptor(observer, options.resolver);
12
- });
13
- },
14
- on: function (event, listener) {
15
- observer.addListener(event, listener);
16
- },
17
- restore: function () {
18
- observer.removeAllListeners();
19
- if (cleanupFns.length === 0) {
20
- throw new Error("Failed to restore patched modules: no patches found. Did you forget to run \".apply()\"?");
21
- }
22
- cleanupFns.forEach(function (restore) { return restore(); });
23
- },
24
- };
25
- }
26
- exports.createInterceptor = createInterceptor;
27
- //# sourceMappingURL=createInterceptor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createInterceptor.js","sourceRoot":"","sources":["../src/createInterceptor.ts"],"names":[],"mappings":";;;AAEA,6DAAyD;AAwEzD,SAAgB,iBAAiB,CAAC,OAA2B;IAC3D,IAAM,QAAQ,GAAG,IAAI,yCAAkB,EAAwB,CAAA;IAC/D,IAAI,UAAU,GAA2B,EAAE,CAAA;IAE3C,OAAO;QACL,KAAK;YACH,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAC,WAAW;gBAC3C,OAAO,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;YAChD,CAAC,CAAC,CAAA;QACJ,CAAC;QACD,EAAE,YAAC,KAAK,EAAE,QAAQ;YAChB,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACvC,CAAC;QACD,OAAO;YACL,QAAQ,CAAC,kBAAkB,EAAE,CAAA;YAE7B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;gBAC3B,MAAM,IAAI,KAAK,CACb,0FAAwF,CACzF,CAAA;aACF;YAED,UAAU,CAAC,OAAO,CAAC,UAAC,OAAO,IAAK,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC;AAzBD,8CAyBC"}
package/lib/remote.d.ts DELETED
@@ -1,21 +0,0 @@
1
- /// <reference types="node" />
2
- import { ChildProcess } from 'child_process';
3
- import { InterceptorApi, InterceptorOptions, Resolver } from './createInterceptor';
4
- export declare type CreateRemoteInterceptorOptions = Omit<InterceptorOptions, 'resolver'>;
5
- export declare type RemoteResolverApi = Pick<InterceptorApi, 'on'>;
6
- export interface CreateRemoteResolverOptions {
7
- process: ChildProcess;
8
- resolver: Resolver;
9
- }
10
- /**
11
- * Creates a remote request interceptor that delegates
12
- * the mocked response resolution to the parent process.
13
- * The parent process must establish a remote resolver
14
- * by calling `createRemoteResolver` function.
15
- */
16
- export declare function createRemoteInterceptor(options: CreateRemoteInterceptorOptions): InterceptorApi;
17
- /**
18
- * Creates a response resolver function attached to the given `ChildProcess`.
19
- * The child process must establish a remote interceptor by calling `createRemoteInterceptor` function.
20
- */
21
- export declare function createRemoteResolver(options: CreateRemoteResolverOptions): RemoteResolverApi;