@mswjs/interceptors 0.21.1 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ClientRequest/package.json +6 -0
- package/RemoteHttpInterceptor/package.json +6 -0
- package/XMLHttpRequest/package.json +6 -0
- package/fetch/package.json +6 -0
- package/lib/browser/interceptors/XMLHttpRequest/index.js +0 -4
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +0 -4
- package/lib/node/RemoteHttpInterceptor.js +11 -15
- package/lib/node/RemoteHttpInterceptor.mjs +5 -9
- package/lib/node/{chunk-ZSI7MX3V.mjs → chunk-37CATPNG.mjs} +0 -34
- package/lib/node/{chunk-ZWCZGO3W.mjs → chunk-CYWTKHFI.mjs} +2 -7
- package/lib/node/{chunk-CIN5URNI.mjs → chunk-G6ZTHYZQ.mjs} +1 -1
- package/lib/node/{chunk-HDUJCCWF.js → chunk-GGD5JOGB.js} +9 -14
- package/lib/node/{chunk-JISWS3Y3.mjs → chunk-KZEQH4YW.mjs} +1 -1
- package/lib/node/{chunk-UVNTVJHD.js → chunk-PRX3F52M.js} +17 -17
- package/lib/node/{chunk-KZJG2UW7.js → chunk-Q56TMOP5.js} +2 -2
- package/lib/node/{chunk-6GWWOJ23.js → chunk-SNNL2EXF.js} +3 -3
- package/lib/node/{chunk-Z5JAVEOB.mjs → chunk-SWJ33XIS.mjs} +10 -10
- package/lib/node/{chunk-QMIXLBOU.js → chunk-WWHITCCI.js} +2 -36
- package/lib/node/index.js +4 -4
- package/lib/node/index.mjs +3 -3
- package/lib/node/interceptors/ClientRequest/index.js +3 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +2 -3
- package/lib/node/interceptors/XMLHttpRequest/index.js +4 -5
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -4
- package/lib/node/interceptors/fetch/index.js +2 -2
- package/lib/node/interceptors/fetch/index.mjs +1 -1
- package/package.json +16 -10
- package/src/BatchInterceptor.test.ts +8 -7
- package/src/Interceptor.test.ts +6 -5
- package/src/RemoteHttpInterceptor.ts +0 -1
- package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +107 -85
- package/src/interceptors/ClientRequest/NodeClientRequest.ts +14 -6
- package/src/interceptors/ClientRequest/index.test.ts +20 -8
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +2 -1
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +1 -0
- package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -1
- package/src/interceptors/ClientRequest/utils/createResponse.test.ts +1 -3
- package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -1
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +5 -4
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +19 -18
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +6 -5
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +5 -4
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +0 -1
- package/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts +1 -3
- package/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts +4 -5
- package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +0 -1
- package/src/interceptors/fetch/index.ts +1 -2
- package/src/utils/AsyncEventEmitter.test.ts +8 -7
- package/src/utils/bufferUtils.test.ts +1 -0
- package/src/utils/cloneObject.test.ts +6 -5
- package/src/utils/getCleanUrl.test.ts +5 -4
- package/src/utils/getUrlByRequestOptions.test.ts +11 -10
- package/src/utils/getUrlByRequestOptions.ts +14 -1
- package/src/utils/isObject.test.ts +4 -3
- package/src/utils/parseJson.test.ts +3 -2
- package/lib/node/chunk-6V3JXLBF.js +0 -6093
- package/lib/node/chunk-NNVTJLQA.mjs +0 -6093
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClientRequestInterceptor
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-NNVTJLQA.mjs";
|
|
3
|
+
} from "../../chunk-SWJ33XIS.mjs";
|
|
5
4
|
import "../../chunk-STA6QBYM.mjs";
|
|
6
|
-
import "../../chunk-
|
|
5
|
+
import "../../chunk-37CATPNG.mjs";
|
|
7
6
|
export {
|
|
8
7
|
ClientRequestInterceptor
|
|
9
8
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../../chunk-
|
|
5
|
-
require('../../chunk-6V3JXLBF.js');
|
|
3
|
+
var _chunkGGD5JOGBjs = require('../../chunk-GGD5JOGB.js');
|
|
4
|
+
require('../../chunk-SNNL2EXF.js');
|
|
6
5
|
require('../../chunk-VQ4DZOBB.js');
|
|
7
6
|
require('../../chunk-ZJOF5MEZ.js');
|
|
8
|
-
require('../../chunk-
|
|
7
|
+
require('../../chunk-WWHITCCI.js');
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
exports.XMLHttpRequestInterceptor =
|
|
10
|
+
exports.XMLHttpRequestInterceptor = _chunkGGD5JOGBjs.XMLHttpRequestInterceptor;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
XMLHttpRequestInterceptor
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
5
|
-
import "../../chunk-NNVTJLQA.mjs";
|
|
3
|
+
} from "../../chunk-CYWTKHFI.mjs";
|
|
4
|
+
import "../../chunk-G6ZTHYZQ.mjs";
|
|
6
5
|
import "../../chunk-GFH37L5D.mjs";
|
|
7
6
|
import "../../chunk-STA6QBYM.mjs";
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
import "../../chunk-37CATPNG.mjs";
|
|
9
8
|
export {
|
|
10
9
|
XMLHttpRequestInterceptor
|
|
11
10
|
};
|
|
@@ -7,11 +7,11 @@ var _chunkVQ4DZOBBjs = require('../../chunk-VQ4DZOBB.js');
|
|
|
7
7
|
var _chunkZJOF5MEZjs = require('../../chunk-ZJOF5MEZ.js');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkWWHITCCIjs = require('../../chunk-WWHITCCI.js');
|
|
11
11
|
|
|
12
12
|
// src/interceptors/fetch/index.ts
|
|
13
13
|
var _outvariant = require('outvariant');
|
|
14
|
-
var _FetchInterceptor = class extends
|
|
14
|
+
var _FetchInterceptor = class extends _chunkWWHITCCIjs.Interceptor {
|
|
15
15
|
constructor() {
|
|
16
16
|
super(_FetchInterceptor.symbol);
|
|
17
17
|
}
|
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.
|
|
4
|
+
"version": "0.22.1",
|
|
5
5
|
"main": "./lib/node/index.js",
|
|
6
6
|
"module": "./lib/node/index.mjs",
|
|
7
7
|
"types": "./lib/node/index.d.ts",
|
|
@@ -54,15 +54,15 @@
|
|
|
54
54
|
"author": "Artem Zakharchenko",
|
|
55
55
|
"license": "MIT",
|
|
56
56
|
"engines": {
|
|
57
|
-
"node": ">=
|
|
57
|
+
"node": ">=18"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"start": "tsc --build -w",
|
|
61
|
-
"test": "yarn test:
|
|
62
|
-
"test:
|
|
61
|
+
"test": "yarn test:unit && yarn test:integration",
|
|
62
|
+
"test:unit": "vitest run",
|
|
63
63
|
"test:integration": "yarn test:integration:node && yarn test:integration:browser",
|
|
64
|
-
"test:integration:node": "
|
|
65
|
-
"test:integration:browser": "
|
|
64
|
+
"test:integration:node": "vitest run -c test/vitest.config.js",
|
|
65
|
+
"test:integration:browser": "playwright test -c test/playwright.config.ts",
|
|
66
66
|
"clean": "rimraf lib",
|
|
67
67
|
"build": "yarn clean && cross-env NODE_ENV=production tsup --splitting",
|
|
68
68
|
"prepare": "yarn simple-git-hooks init",
|
|
@@ -72,7 +72,11 @@
|
|
|
72
72
|
"files": [
|
|
73
73
|
"lib",
|
|
74
74
|
"README.md",
|
|
75
|
-
"src"
|
|
75
|
+
"src",
|
|
76
|
+
"ClientRequest",
|
|
77
|
+
"fetch",
|
|
78
|
+
"RemoteHttpInterceptor",
|
|
79
|
+
"XMLHttpRequest"
|
|
76
80
|
],
|
|
77
81
|
"repository": {
|
|
78
82
|
"type": "git",
|
|
@@ -83,7 +87,7 @@
|
|
|
83
87
|
"@commitlint/config-conventional": "^16.0.0",
|
|
84
88
|
"@open-draft/test-server": "^0.4.2",
|
|
85
89
|
"@ossjs/release": "^0.4.0",
|
|
86
|
-
"@
|
|
90
|
+
"@playwright/test": "^1.31.1",
|
|
87
91
|
"@types/cors": "^2.8.12",
|
|
88
92
|
"@types/express": "^4.17.13",
|
|
89
93
|
"@types/express-rate-limit": "^6.0.0",
|
|
@@ -104,7 +108,7 @@
|
|
|
104
108
|
"got": "^11.8.3",
|
|
105
109
|
"jest": "^27.4.3",
|
|
106
110
|
"node-fetch": "2.6.7",
|
|
107
|
-
"
|
|
111
|
+
"playwright": "^1.31.1",
|
|
108
112
|
"rimraf": "^3.0.2",
|
|
109
113
|
"simple-git-hooks": "^2.7.0",
|
|
110
114
|
"superagent": "^6.1.0",
|
|
@@ -112,8 +116,10 @@
|
|
|
112
116
|
"ts-jest": "^27.1.1",
|
|
113
117
|
"tsup": "^6.5.0",
|
|
114
118
|
"typescript": "^4.9.4",
|
|
119
|
+
"vitest": "^0.28.5",
|
|
115
120
|
"wait-for-expect": "^3.0.2",
|
|
116
|
-
"web-encoding": "^1.1.5"
|
|
121
|
+
"web-encoding": "^1.1.5",
|
|
122
|
+
"webpack-http-server": "^0.5.0"
|
|
117
123
|
},
|
|
118
124
|
"dependencies": {
|
|
119
125
|
"@open-draft/deferred-promise": "^2.1.0",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { vi, it, expect, afterEach } from 'vitest'
|
|
1
2
|
import { Interceptor } from './Interceptor'
|
|
2
3
|
import { BatchInterceptor } from './BatchInterceptor'
|
|
3
4
|
|
|
4
5
|
afterEach(() => {
|
|
5
|
-
|
|
6
|
+
vi.resetAllMocks()
|
|
6
7
|
})
|
|
7
8
|
|
|
8
9
|
it('applies child interceptors', () => {
|
|
@@ -28,8 +29,8 @@ it('applies child interceptors', () => {
|
|
|
28
29
|
interceptors: [instances.primary, instances.secondary],
|
|
29
30
|
})
|
|
30
31
|
|
|
31
|
-
const primaryApplySpy =
|
|
32
|
-
const secondaryApplySpy =
|
|
32
|
+
const primaryApplySpy = vi.spyOn(instances.primary, 'apply')
|
|
33
|
+
const secondaryApplySpy = vi.spyOn(instances.secondary, 'apply')
|
|
33
34
|
|
|
34
35
|
interceptor.apply()
|
|
35
36
|
|
|
@@ -62,10 +63,10 @@ it('proxies event listeners to the interceptors', () => {
|
|
|
62
63
|
interceptors: [instances.primary, instances.secondary],
|
|
63
64
|
})
|
|
64
65
|
|
|
65
|
-
const helloListener =
|
|
66
|
+
const helloListener = vi.fn()
|
|
66
67
|
interceptor.on('hello', helloListener)
|
|
67
68
|
|
|
68
|
-
const goodbyeListener =
|
|
69
|
+
const goodbyeListener = vi.fn()
|
|
69
70
|
interceptor.on('goodbye', goodbyeListener)
|
|
70
71
|
|
|
71
72
|
// Emulate the child interceptor emitting events.
|
|
@@ -102,8 +103,8 @@ it('disposes of child interceptors', async () => {
|
|
|
102
103
|
interceptors: [instances.primary, instances.secondary],
|
|
103
104
|
})
|
|
104
105
|
|
|
105
|
-
const primaryDisposeSpy =
|
|
106
|
-
const secondaryDisposeSpy =
|
|
106
|
+
const primaryDisposeSpy = vi.spyOn(instances.primary, 'dispose')
|
|
107
|
+
const secondaryDisposeSpy = vi.spyOn(instances.secondary, 'dispose')
|
|
107
108
|
|
|
108
109
|
interceptor.apply()
|
|
109
110
|
interceptor.dispose()
|
package/src/Interceptor.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, vi, it, expect, afterEach } from 'vitest'
|
|
1
2
|
import {
|
|
2
3
|
Interceptor,
|
|
3
4
|
getGlobalSymbol,
|
|
@@ -84,7 +85,7 @@ describe('readyState', () => {
|
|
|
84
85
|
describe('apply', () => {
|
|
85
86
|
it('does not apply the same interceptor multiple times', () => {
|
|
86
87
|
const interceptor = new Interceptor(symbol)
|
|
87
|
-
const setupSpy =
|
|
88
|
+
const setupSpy = vi.spyOn(
|
|
88
89
|
interceptor,
|
|
89
90
|
// @ts-expect-error Protected property spy.
|
|
90
91
|
'setup'
|
|
@@ -109,7 +110,7 @@ describe('apply', () => {
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
const interceptor = new MyInterceptor(Symbol('test'))
|
|
112
|
-
const setupSpy =
|
|
113
|
+
const setupSpy = vi.spyOn(
|
|
113
114
|
interceptor,
|
|
114
115
|
// @ts-expect-error Protected property spy.
|
|
115
116
|
'setup'
|
|
@@ -124,11 +125,11 @@ describe('apply', () => {
|
|
|
124
125
|
const secondInterceptor = new Interceptor(symbol)
|
|
125
126
|
|
|
126
127
|
firstInterceptor.apply()
|
|
127
|
-
const firstListener =
|
|
128
|
+
const firstListener = vi.fn()
|
|
128
129
|
firstInterceptor.on('test', firstListener)
|
|
129
130
|
|
|
130
131
|
secondInterceptor.apply()
|
|
131
|
-
const secondListener =
|
|
132
|
+
const secondListener = vi.fn()
|
|
132
133
|
secondInterceptor.on('test', secondListener)
|
|
133
134
|
|
|
134
135
|
// Emitting event in the first interceptor will bubble to the second one.
|
|
@@ -149,7 +150,7 @@ describe('dispose', () => {
|
|
|
149
150
|
const interceptor = new Interceptor(symbol)
|
|
150
151
|
|
|
151
152
|
interceptor.apply()
|
|
152
|
-
const listener =
|
|
153
|
+
const listener = vi.fn()
|
|
153
154
|
interceptor.on('test', listener)
|
|
154
155
|
interceptor.dispose()
|
|
155
156
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ChildProcess } from 'child_process'
|
|
2
|
-
import { Request, Response } from '@remix-run/web-fetch'
|
|
3
2
|
import { Headers, HeadersObject, headersToObject } from 'headers-polyfill'
|
|
4
3
|
import { HttpRequestEventMap } from './glossary'
|
|
5
4
|
import { Interceptor } from './Interceptor'
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* @jest-environment node
|
|
3
|
-
*/
|
|
1
|
+
import { vi, it, expect, beforeAll, afterAll } from 'vitest'
|
|
4
2
|
import { debug } from 'debug'
|
|
5
|
-
import
|
|
3
|
+
import express from 'express'
|
|
4
|
+
import { IncomingMessage } from 'http'
|
|
6
5
|
import { HttpServer } from '@open-draft/test-server/http'
|
|
7
|
-
import {
|
|
6
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
8
7
|
import { NodeClientRequest } from './NodeClientRequest'
|
|
9
8
|
import { getIncomingMessageBody } from './utils/getIncomingMessageBody'
|
|
10
9
|
import { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs'
|
|
@@ -37,7 +36,7 @@ afterAll(async () => {
|
|
|
37
36
|
await httpServer.close()
|
|
38
37
|
})
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
it('gracefully finishes the request when it has a mocked response', async () => {
|
|
41
40
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
42
41
|
const request = new NodeClientRequest(
|
|
43
42
|
normalizeClientRequestArgs('http:', 'http://any.thing', {
|
|
@@ -60,26 +59,28 @@ test('gracefully finishes the request when it has a mocked response', (done) =>
|
|
|
60
59
|
)
|
|
61
60
|
})
|
|
62
61
|
|
|
63
|
-
request.
|
|
64
|
-
// Request must be marked as finished.
|
|
65
|
-
expect(request.finished).toEqual(true)
|
|
66
|
-
expect(request.writableEnded).toEqual(true)
|
|
67
|
-
expect(request.writableFinished).toEqual(true)
|
|
68
|
-
expect(request.writableCorked).toEqual(0)
|
|
62
|
+
request.end()
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
65
|
+
request.on('response', async (response) => {
|
|
66
|
+
responseReceived.resolve(response)
|
|
67
|
+
})
|
|
68
|
+
const response = await responseReceived
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
// Request must be marked as finished.
|
|
71
|
+
expect(request.finished).toEqual(true)
|
|
72
|
+
expect(request.writableEnded).toEqual(true)
|
|
73
|
+
expect(request.writableFinished).toEqual(true)
|
|
74
|
+
expect(request.writableCorked).toEqual(0)
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
expect(response.statusCode).toEqual(301)
|
|
77
|
+
expect(response.headers).toHaveProperty('x-custom-header', 'yes')
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
const text = await getIncomingMessageBody(response)
|
|
80
|
+
expect(text).toEqual('mocked-response')
|
|
80
81
|
})
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
it('responds with a mocked response when requesting an existing hostname', async () => {
|
|
83
84
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
84
85
|
const request = new NodeClientRequest(
|
|
85
86
|
normalizeClientRequestArgs('http:', httpServer.http.url('/comment')),
|
|
@@ -93,19 +94,21 @@ test('responds with a mocked response when requesting an existing hostname', (do
|
|
|
93
94
|
request.respondWith(new Response('mocked-response', { status: 201 }))
|
|
94
95
|
})
|
|
95
96
|
|
|
96
|
-
request.
|
|
97
|
-
expect(response.statusCode).toEqual(201)
|
|
98
|
-
|
|
99
|
-
const text = await getIncomingMessageBody(response)
|
|
100
|
-
expect(text).toEqual('mocked-response')
|
|
97
|
+
request.end()
|
|
101
98
|
|
|
102
|
-
|
|
99
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
100
|
+
request.on('response', async (response) => {
|
|
101
|
+
responseReceived.resolve(response)
|
|
103
102
|
})
|
|
103
|
+
const response = await responseReceived
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
expect(response.statusCode).toEqual(201)
|
|
106
|
+
|
|
107
|
+
const text = await getIncomingMessageBody(response)
|
|
108
|
+
expect(text).toEqual('mocked-response')
|
|
106
109
|
})
|
|
107
110
|
|
|
108
|
-
|
|
111
|
+
it('performs the request as-is given resolver returned no mocked response', async () => {
|
|
109
112
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
110
113
|
const request = new NodeClientRequest(
|
|
111
114
|
normalizeClientRequestArgs('http:', httpServer.http.url('/comment'), {
|
|
@@ -117,40 +120,44 @@ test('performs the request as-is given resolver returned no mocked response', (d
|
|
|
117
120
|
}
|
|
118
121
|
)
|
|
119
122
|
|
|
120
|
-
request.
|
|
121
|
-
expect(request.finished).toEqual(true)
|
|
122
|
-
expect(request.writableEnded).toEqual(true)
|
|
123
|
+
request.end()
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
126
|
+
request.on('response', async (response) => {
|
|
127
|
+
responseReceived.resolve(response)
|
|
128
|
+
})
|
|
129
|
+
const response = await responseReceived
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
expect(request.finished).toEqual(true)
|
|
132
|
+
expect(request.writableEnded).toEqual(true)
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
expect(response.statusCode).toEqual(200)
|
|
135
|
+
expect(response.statusMessage).toEqual('OK')
|
|
136
|
+
expect(response.headers).toHaveProperty('x-powered-by', 'Express')
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
const text = await getIncomingMessageBody(response)
|
|
139
|
+
expect(text).toEqual('original-response')
|
|
135
140
|
})
|
|
136
141
|
|
|
137
|
-
|
|
142
|
+
it('emits the ENOTFOUND error connecting to a non-existing hostname given no mocked response', async () => {
|
|
138
143
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
139
144
|
const request = new NodeClientRequest(
|
|
140
145
|
normalizeClientRequestArgs('http:', 'http://non-existing-url.com'),
|
|
141
146
|
{ emitter, log }
|
|
142
147
|
)
|
|
148
|
+
request.end()
|
|
143
149
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
done()
|
|
150
|
+
const errorReceived = new DeferredPromise<NodeJS.ErrnoException>()
|
|
151
|
+
request.on('error', async (error) => {
|
|
152
|
+
errorReceived.resolve(error)
|
|
148
153
|
})
|
|
154
|
+
const error = await errorReceived
|
|
149
155
|
|
|
150
|
-
|
|
156
|
+
expect(error.code).toEqual('ENOTFOUND')
|
|
157
|
+
expect(error.syscall).toEqual('getaddrinfo')
|
|
151
158
|
})
|
|
152
159
|
|
|
153
|
-
|
|
160
|
+
it('emits the ECONNREFUSED error connecting to an inactive server given no mocked response', async () => {
|
|
154
161
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
155
162
|
const request = new NodeClientRequest(
|
|
156
163
|
normalizeClientRequestArgs('http:', 'http://127.0.0.1:12345'),
|
|
@@ -160,21 +167,25 @@ test('emits the ECONNREFUSED error connecting to an inactive server given no moc
|
|
|
160
167
|
}
|
|
161
168
|
)
|
|
162
169
|
|
|
163
|
-
request.
|
|
164
|
-
expect(error.code).toEqual('ECONNREFUSED')
|
|
165
|
-
expect(error.syscall).toEqual('connect')
|
|
166
|
-
expect(error.address).toEqual('127.0.0.1')
|
|
167
|
-
expect(error.port).toEqual(12345)
|
|
170
|
+
request.end()
|
|
168
171
|
|
|
169
|
-
|
|
172
|
+
const errorReceived = new DeferredPromise<ErrorConnectionRefused>()
|
|
173
|
+
request.on('error', async (error: ErrorConnectionRefused) => {
|
|
174
|
+
errorReceived.resolve(error)
|
|
170
175
|
})
|
|
171
|
-
|
|
172
176
|
request.end()
|
|
177
|
+
|
|
178
|
+
const error = await errorReceived
|
|
179
|
+
|
|
180
|
+
expect(error.code).toEqual('ECONNREFUSED')
|
|
181
|
+
expect(error.syscall).toEqual('connect')
|
|
182
|
+
expect(error.address).toEqual('127.0.0.1')
|
|
183
|
+
expect(error.port).toEqual(12345)
|
|
173
184
|
})
|
|
174
185
|
|
|
175
|
-
|
|
186
|
+
it('does not emit ENOTFOUND error connecting to an inactive server given mocked response', async () => {
|
|
176
187
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
177
|
-
const handleError =
|
|
188
|
+
const handleError = vi.fn()
|
|
178
189
|
const request = new NodeClientRequest(
|
|
179
190
|
normalizeClientRequestArgs('http:', 'http://non-existing-url.com'),
|
|
180
191
|
{ emitter, log }
|
|
@@ -187,19 +198,24 @@ test('does not emit ENOTFOUND error connecting to an inactive server given mocke
|
|
|
187
198
|
)
|
|
188
199
|
})
|
|
189
200
|
|
|
201
|
+
request.end()
|
|
202
|
+
|
|
190
203
|
request.on('error', handleError)
|
|
204
|
+
|
|
205
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
191
206
|
request.on('response', (response) => {
|
|
192
|
-
|
|
193
|
-
expect(response.statusCode).toEqual(200)
|
|
194
|
-
expect(response.statusMessage).toEqual('Works')
|
|
195
|
-
done()
|
|
207
|
+
responseReceived.resolve(response)
|
|
196
208
|
})
|
|
197
|
-
|
|
209
|
+
const response = await responseReceived
|
|
210
|
+
|
|
211
|
+
expect(handleError).not.toHaveBeenCalled()
|
|
212
|
+
expect(response.statusCode).toEqual(200)
|
|
213
|
+
expect(response.statusMessage).toEqual('Works')
|
|
198
214
|
})
|
|
199
215
|
|
|
200
|
-
|
|
216
|
+
it('does not emit ECONNREFUSED error connecting to an inactive server given mocked response', async () => {
|
|
201
217
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
202
|
-
const handleError =
|
|
218
|
+
const handleError = vi.fn()
|
|
203
219
|
const request = new NodeClientRequest(
|
|
204
220
|
normalizeClientRequestArgs('http:', 'http://localhost:9876'),
|
|
205
221
|
{
|
|
@@ -216,16 +232,20 @@ test('does not emit ECONNREFUSED error connecting to an inactive server given mo
|
|
|
216
232
|
})
|
|
217
233
|
|
|
218
234
|
request.on('error', handleError)
|
|
235
|
+
request.end()
|
|
236
|
+
|
|
237
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
219
238
|
request.on('response', (response) => {
|
|
220
|
-
|
|
221
|
-
expect(response.statusCode).toEqual(200)
|
|
222
|
-
expect(response.statusMessage).toEqual('Works')
|
|
223
|
-
done()
|
|
239
|
+
responseReceived.resolve(response)
|
|
224
240
|
})
|
|
225
|
-
|
|
241
|
+
const response = await responseReceived
|
|
242
|
+
|
|
243
|
+
expect(handleError).not.toHaveBeenCalled()
|
|
244
|
+
expect(response.statusCode).toEqual(200)
|
|
245
|
+
expect(response.statusMessage).toEqual('Works')
|
|
226
246
|
})
|
|
227
247
|
|
|
228
|
-
|
|
248
|
+
it('sends the request body to the server given no mocked response', async () => {
|
|
229
249
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
230
250
|
const request = new NodeClientRequest(
|
|
231
251
|
normalizeClientRequestArgs('http:', httpServer.http.url('/write'), {
|
|
@@ -242,20 +262,21 @@ test('sends the request body to the server given no mocked response', (done) =>
|
|
|
242
262
|
|
|
243
263
|
request.write('one')
|
|
244
264
|
request.write('two')
|
|
265
|
+
request.end('three')
|
|
245
266
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const text = await getIncomingMessageBody(response)
|
|
250
|
-
expect(text).toEqual('onetwothree')
|
|
251
|
-
|
|
252
|
-
done()
|
|
267
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
268
|
+
request.on('response', (response) => {
|
|
269
|
+
responseReceived.resolve(response)
|
|
253
270
|
})
|
|
271
|
+
const response = await responseReceived
|
|
254
272
|
|
|
255
|
-
|
|
273
|
+
expect(response.statusCode).toEqual(200)
|
|
274
|
+
|
|
275
|
+
const text = await getIncomingMessageBody(response)
|
|
276
|
+
expect(text).toEqual('onetwothree')
|
|
256
277
|
})
|
|
257
278
|
|
|
258
|
-
|
|
279
|
+
it('does not send request body to the original server given mocked response', async () => {
|
|
259
280
|
const emitter = new AsyncEventEmitter<HttpRequestEventMap>()
|
|
260
281
|
const request = new NodeClientRequest(
|
|
261
282
|
normalizeClientRequestArgs('http:', httpServer.http.url('/write'), {
|
|
@@ -274,15 +295,16 @@ test('does not send request body to the original server given mocked response',
|
|
|
274
295
|
|
|
275
296
|
request.write('one')
|
|
276
297
|
request.write('two')
|
|
298
|
+
request.end()
|
|
277
299
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const text = await getIncomingMessageBody(response)
|
|
282
|
-
expect(text).toEqual('mock created!')
|
|
283
|
-
|
|
284
|
-
done()
|
|
300
|
+
const responseReceived = new DeferredPromise<IncomingMessage>()
|
|
301
|
+
request.on('response', (response) => {
|
|
302
|
+
responseReceived.resolve(response)
|
|
285
303
|
})
|
|
304
|
+
const response = await responseReceived
|
|
286
305
|
|
|
287
|
-
|
|
306
|
+
expect(response.statusCode).toEqual(301)
|
|
307
|
+
|
|
308
|
+
const text = await getIncomingMessageBody(response)
|
|
309
|
+
expect(text).toEqual('mock created!')
|
|
288
310
|
})
|
|
@@ -177,6 +177,20 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
177
177
|
}).then(([resolverException, mockedResponse]) => {
|
|
178
178
|
this.log('the listeners promise awaited!')
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* @fixme We are in the "end()" method that still executes in parallel
|
|
182
|
+
* to our mocking logic here. This can be solved by migrating to the
|
|
183
|
+
* Proxy-based approach and deferring the passthrough "end()" properly.
|
|
184
|
+
* @see https://github.com/mswjs/interceptors/issues/346
|
|
185
|
+
*/
|
|
186
|
+
if (!this.headersSent) {
|
|
187
|
+
// Forward any request headers that the "request" listener
|
|
188
|
+
// may have modified before proceeding with this request.
|
|
189
|
+
for (const [headerName, headerValue] of capturedRequest.headers) {
|
|
190
|
+
this.setHeader(headerName, headerValue)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
180
194
|
// Halt the request whenever the resolver throws an exception.
|
|
181
195
|
if (resolverException) {
|
|
182
196
|
this.log(
|
|
@@ -189,12 +203,6 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
189
203
|
return this
|
|
190
204
|
}
|
|
191
205
|
|
|
192
|
-
// Forward any request headers that the "request" listener
|
|
193
|
-
// may have modified before proceeding with this request.
|
|
194
|
-
for (const [headerName, headerValue] of capturedRequest.headers) {
|
|
195
|
-
this.setHeader(headerName, headerValue)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
206
|
if (mockedResponse) {
|
|
199
207
|
const responseClone = mockedResponse.clone()
|
|
200
208
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
+
import http from 'http'
|
|
2
3
|
import { HttpServer } from '@open-draft/test-server/http'
|
|
3
|
-
import {
|
|
4
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
4
5
|
import { ClientRequestInterceptor } from '.'
|
|
5
6
|
|
|
6
7
|
const httpServer = new HttpServer((app) => {
|
|
@@ -15,8 +16,8 @@ const httpServer = new HttpServer((app) => {
|
|
|
15
16
|
const interceptor = new ClientRequestInterceptor()
|
|
16
17
|
|
|
17
18
|
beforeAll(async () => {
|
|
18
|
-
await httpServer.listen()
|
|
19
19
|
interceptor.apply()
|
|
20
|
+
await httpServer.listen()
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
afterAll(async () => {
|
|
@@ -24,22 +25,33 @@ afterAll(async () => {
|
|
|
24
25
|
await httpServer.close()
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
it('forbids calling "respondWith" multiple times for the same request', (
|
|
28
|
+
it('forbids calling "respondWith" multiple times for the same request', async () => {
|
|
28
29
|
const requestUrl = httpServer.http.url('/')
|
|
29
30
|
|
|
30
|
-
interceptor.on('request', (request)
|
|
31
|
+
interceptor.on('request', function firstRequestListener(request) {
|
|
31
32
|
request.respondWith(new Response())
|
|
32
33
|
})
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
const secondRequestEmitted = new DeferredPromise<void>()
|
|
36
|
+
interceptor.on('request', function secondRequestListener(request) {
|
|
35
37
|
expect(() =>
|
|
36
38
|
request.respondWith(new Response(null, { status: 301 }))
|
|
37
39
|
).toThrow(
|
|
38
40
|
`Failed to respond to "GET ${requestUrl}" request: the "request" event has already been responded to.`
|
|
39
41
|
)
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
secondRequestEmitted.resolve()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const request = http.get(requestUrl)
|
|
47
|
+
await secondRequestEmitted
|
|
48
|
+
|
|
49
|
+
const responseReceived = new DeferredPromise<http.IncomingMessage>()
|
|
50
|
+
request.on('response', (response) => {
|
|
51
|
+
responseReceived.resolve(response)
|
|
42
52
|
})
|
|
43
53
|
|
|
44
|
-
|
|
54
|
+
const response = await responseReceived
|
|
55
|
+
expect(response.statusCode).toBe(200)
|
|
56
|
+
expect(response.statusMessage).toBe('')
|
|
45
57
|
})
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { Socket } from 'net'
|
|
2
3
|
import { IncomingMessage } from 'http'
|
|
3
4
|
import { Stream, Readable, EventEmitter } from 'stream'
|
|
4
5
|
import { cloneIncomingMessage, IS_CLONE } from './cloneIncomingMessage'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
it('clones a given IncomingMessage', () => {
|
|
7
8
|
const message = new IncomingMessage(new Socket())
|
|
8
9
|
message.statusCode = 200
|
|
9
10
|
message.statusMessage = 'OK'
|