@mswjs/interceptors 0.14.1 → 0.15.2

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 (90) 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 +65 -16
  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 +7 -7
  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 +150 -99
  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
@@ -1,19 +1,18 @@
1
1
  import { debug } from 'debug'
2
2
  import { ClientRequest } from 'http'
3
- import { Observer, Resolver } from '../../createInterceptor'
4
- import { NodeClientRequest, Protocol } from './NodeClientRequest'
3
+ import {
4
+ NodeClientOptions,
5
+ NodeClientRequest,
6
+ Protocol,
7
+ } from './NodeClientRequest'
5
8
  import {
6
9
  normalizeClientRequestArgs,
7
10
  ClientRequestArgs,
8
11
  } from './utils/normalizeClientRequestArgs'
9
12
 
10
- const log = debug('http.request')
13
+ const log = debug('http request')
11
14
 
12
- export function request(
13
- protocol: Protocol,
14
- resolver: Resolver,
15
- observer: Observer
16
- ) {
15
+ export function request(protocol: Protocol, options: NodeClientOptions) {
17
16
  return (...args: ClientRequestArgs): ClientRequest => {
18
17
  log('request call (protocol "%s"):', protocol, args)
19
18
 
@@ -21,9 +20,6 @@ export function request(
21
20
  `${protocol}:`,
22
21
  ...args
23
22
  )
24
- return new NodeClientRequest(clientRequestArgs, {
25
- observer,
26
- resolver,
27
- })
23
+ return new NodeClientRequest(clientRequestArgs, options)
28
24
  }
29
25
  }
@@ -0,0 +1,43 @@
1
+ import * as http from 'http'
2
+ import { HttpServer } from '@open-draft/test-server/http'
3
+ import { ClientRequestInterceptor } from '.'
4
+
5
+ const httpServer = new HttpServer((app) => {
6
+ app.get('/', (_req, res) => {
7
+ res.status(200).send('/')
8
+ })
9
+ app.get('/get', (_req, res) => {
10
+ res.status(200).send('/get')
11
+ })
12
+ })
13
+
14
+ const interceptor = new ClientRequestInterceptor()
15
+
16
+ beforeAll(async () => {
17
+ await httpServer.listen()
18
+
19
+ interceptor.apply()
20
+ })
21
+
22
+ afterAll(async () => {
23
+ interceptor.dispose()
24
+ await httpServer.close()
25
+ })
26
+
27
+ it('forbids calling "respondWith" multiple times for the same request', (done) => {
28
+ const requestUrl = httpServer.http.url('/')
29
+
30
+ interceptor.on('request', (request) => {
31
+ request.respondWith({ status: 200 })
32
+ })
33
+
34
+ interceptor.on('request', (request) => {
35
+ expect(() => request.respondWith({ status: 301 })).toThrow(
36
+ `Failed to respond to "GET ${requestUrl}" request: the "request" event has already been responded to.`
37
+ )
38
+
39
+ done()
40
+ })
41
+
42
+ http.get(requestUrl)
43
+ })
@@ -1,61 +1,61 @@
1
- import { debug } from 'debug'
2
1
  import http from 'http'
3
2
  import https from 'https'
4
- import { Interceptor } from '../../createInterceptor'
3
+ import { HttpRequestEventMap } from '../../glossary'
4
+ import { Interceptor } from '../../Interceptor'
5
+ import { AsyncEventEmitter } from '../../utils/AsyncEventEmitter'
5
6
  import { get } from './http.get'
6
- import { Protocol } from './NodeClientRequest'
7
7
  import { request } from './http.request'
8
+ import { NodeClientOptions, Protocol } from './NodeClientRequest'
8
9
 
9
- const log = debug('http override')
10
+ export type ClientRequestEmitter = AsyncEventEmitter<HttpRequestEventMap>
10
11
 
11
- export type RequestModule = typeof http | typeof https
12
- type PureModules = Map<
13
- Protocol,
14
- {
15
- module: RequestModule
16
- get: typeof http.get
17
- request: typeof http.request
18
- }
19
- >
12
+ export type ClientRequestModules = Map<Protocol, typeof http | typeof https>
20
13
 
21
14
  /**
22
- * Intercepts requests issued by native "http" and "https" modules.
15
+ * Intercept requests made via the `ClientRequest` class.
16
+ * Such requests include `http.get`, `https.request`, etc.
23
17
  */
24
- export const interceptClientRequest: Interceptor = (observer, resolver) => {
25
- const pureModules: PureModules = new Map()
26
- const modules: [Protocol, RequestModule][] = [
27
- ['http', http],
28
- ['https', https],
29
- ]
30
-
31
- for (const [protocol, requestModule] of modules) {
32
- log('patching the "%s" module...', protocol)
33
-
34
- pureModules.set(protocol, {
35
- module: requestModule,
36
- request: requestModule.request,
37
- get: requestModule.get,
38
- })
39
-
40
- // @ts-ignore Call signature overloads are incompatible.
41
- requestModule.request =
42
- // Force a line-break to prevent ignoring the "request" call.
43
- request(protocol, resolver, observer)
44
-
45
- // @ts-ignore Call signature overloads are incompatible.
46
- requestModule.get =
47
- // Force a line-break to prevent ignoring the "get" call.
48
- get(protocol, resolver, observer)
18
+ export class ClientRequestInterceptor extends Interceptor<HttpRequestEventMap> {
19
+ static symbol = Symbol('http')
20
+ private modules: ClientRequestModules
21
+
22
+ constructor() {
23
+ super(ClientRequestInterceptor.symbol)
24
+
25
+ this.modules = new Map()
26
+ this.modules.set('http', http)
27
+ this.modules.set('https', https)
49
28
  }
50
29
 
51
- return () => {
52
- log('done, restoring modules...')
30
+ protected setup(): void {
31
+ const log = this.log.extend('setup')
53
32
 
54
- for (const requestModule of pureModules.values()) {
55
- requestModule.module.get = requestModule.get
56
- requestModule.module.request = requestModule.request
57
- }
33
+ for (const [protocol, requestModule] of this.modules) {
34
+ const { request: pureRequest, get: pureGet } = requestModule
35
+
36
+ this.subscriptions.push(() => {
37
+ requestModule.request = pureRequest
38
+ requestModule.get = pureGet
58
39
 
59
- pureModules.clear()
40
+ log('native "%s" module restored!', protocol)
41
+ })
42
+
43
+ const options: NodeClientOptions = {
44
+ emitter: this.emitter,
45
+ log: this.log,
46
+ }
47
+
48
+ // @ts-ignore
49
+ requestModule.request =
50
+ // Force a line break.
51
+ request(protocol, options)
52
+
53
+ // @ts-ignore
54
+ requestModule.get =
55
+ // Force a line break.
56
+ get(protocol, options)
57
+
58
+ log('native "%s" module patched!', protocol)
59
+ }
60
60
  }
61
61
  }
@@ -42,3 +42,12 @@ test('returns utf8 string given a gzipped response body with incorrect "content-
42
42
 
43
43
  expect(await pendingResponseBody).toEqual('three')
44
44
  })
45
+
46
+ test('returns empty string given an empty body', async () => {
47
+ const message = new IncomingMessage(new Socket())
48
+
49
+ const pendingResponseBody = getIncomingMessageBody(message)
50
+ message.emit('end')
51
+
52
+ expect(await pendingResponseBody).toEqual('')
53
+ })
@@ -25,9 +25,16 @@ export function getIncomingMessageBody(
25
25
  stream.setEncoding(encoding)
26
26
  log('using encoding:', encoding)
27
27
 
28
- stream.once('data', (responseBody) => {
28
+ let body = '';
29
+
30
+ stream.on('data', (responseBody) => {
29
31
  log('response body read:', responseBody)
30
- resolve(responseBody)
32
+ body += responseBody;
33
+ })
34
+
35
+ stream.once('end', () => {
36
+ log('response body end');
37
+ resolve(body);
31
38
  })
32
39
 
33
40
  stream.once('error', (error) => {