nock 11.6.0 → 11.7.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.
- package/README.md +1 -0
- package/lib/common.js +2 -9
- package/lib/intercepted_request_router.js +6 -5
- package/lib/match_body.js +2 -5
- package/lib/playback_interceptor.js +5 -5
- package/lib/recorder.js +27 -30
- package/lib/scope.js +3 -2
- package/lib/socket.js +16 -0
- package/package.json +7 -4
- package/types/index.d.ts +1 -0
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ For instance, if a module performs HTTP requests to a CouchDB server or makes HT
|
|
|
58
58
|
- [Expectations](#expectations)
|
|
59
59
|
- [.isDone()](#isdone)
|
|
60
60
|
- [.cleanAll()](#cleanall)
|
|
61
|
+
- [.abortPendingRequests()](#abortpendingrequests)
|
|
61
62
|
- [.persist()](#persist)
|
|
62
63
|
- [.pendingMocks()](#pendingmocks)
|
|
63
64
|
- [.activeMocks()](#activemocks)
|
package/lib/common.js
CHANGED
|
@@ -38,23 +38,16 @@ function normalizeRequestOptions(options) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Returns
|
|
41
|
+
* Returns true if the data contained in buffer can be reconstructed
|
|
42
42
|
* from its utf8 representation.
|
|
43
43
|
*
|
|
44
|
-
* TODO: Reverse the semantics of this method and refactor calling code
|
|
45
|
-
* accordingly. We've inadvertently gotten it flipped.
|
|
46
|
-
*
|
|
47
44
|
* @param {Object} buffer - a Buffer object
|
|
48
45
|
* @returns {boolean}
|
|
49
46
|
*/
|
|
50
47
|
function isUtf8Representable(buffer) {
|
|
51
|
-
if (!Buffer.isBuffer(buffer)) {
|
|
52
|
-
return false
|
|
53
|
-
}
|
|
54
|
-
|
|
55
48
|
const utfEncodedBuffer = buffer.toString('utf8')
|
|
56
49
|
const reconstructedBuffer = Buffer.from(utfEncodedBuffer, 'utf8')
|
|
57
|
-
return
|
|
50
|
+
return reconstructedBuffer.equals(buffer)
|
|
58
51
|
}
|
|
59
52
|
|
|
60
53
|
// Array where all information about all the overridden requests are held.
|
|
@@ -30,7 +30,7 @@ class InterceptedRequestRouter {
|
|
|
30
30
|
}
|
|
31
31
|
this.interceptors = interceptors
|
|
32
32
|
|
|
33
|
-
this.socket = new Socket(
|
|
33
|
+
this.socket = new Socket(options)
|
|
34
34
|
this.response = new IncomingMessage(this.socket)
|
|
35
35
|
this.playbackStarted = false
|
|
36
36
|
this.requestBodyBuffers = []
|
|
@@ -231,8 +231,9 @@ class InterceptedRequestRouter {
|
|
|
231
231
|
// Re-update `options` with the current value of `req.path` because badly
|
|
232
232
|
// behaving agents like superagent like to change `req.path` mid-flight.
|
|
233
233
|
path: req.path,
|
|
234
|
-
//
|
|
234
|
+
// Similarly, node-http-proxy will modify headers in flight, so we have
|
|
235
235
|
// to put the headers back into options.
|
|
236
|
+
// https://github.com/nock/nock/pull/1484
|
|
236
237
|
headers: req.getHeaders(),
|
|
237
238
|
// Fixes https://github.com/nock/nock/issues/976
|
|
238
239
|
protocol: `${options.proto}:`,
|
|
@@ -245,11 +246,11 @@ class InterceptedRequestRouter {
|
|
|
245
246
|
const requestBodyBuffer = Buffer.concat(this.requestBodyBuffers)
|
|
246
247
|
// When request body is a binary buffer we internally use in its hexadecimal
|
|
247
248
|
// representation.
|
|
248
|
-
const
|
|
249
|
+
const requestBodyIsUtf8Representable = common.isUtf8Representable(
|
|
249
250
|
requestBodyBuffer
|
|
250
251
|
)
|
|
251
252
|
const requestBodyString = requestBodyBuffer.toString(
|
|
252
|
-
|
|
253
|
+
requestBodyIsUtf8Representable ? 'utf8' : 'hex'
|
|
253
254
|
)
|
|
254
255
|
|
|
255
256
|
const matchedInterceptor = interceptors.find(i =>
|
|
@@ -264,7 +265,7 @@ class InterceptedRequestRouter {
|
|
|
264
265
|
socket,
|
|
265
266
|
options,
|
|
266
267
|
requestBodyString,
|
|
267
|
-
|
|
268
|
+
requestBodyIsUtf8Representable,
|
|
268
269
|
response,
|
|
269
270
|
interceptor: matchedInterceptor,
|
|
270
271
|
})
|
package/lib/match_body.js
CHANGED
|
@@ -11,11 +11,8 @@ module.exports = function matchBody(options, spec, body) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
if (Buffer.isBuffer(spec)) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} else {
|
|
17
|
-
spec = spec.toString('utf8')
|
|
18
|
-
}
|
|
14
|
+
const encoding = common.isUtf8Representable(spec) ? 'utf8' : 'hex'
|
|
15
|
+
spec = spec.toString(encoding)
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
const contentType = (
|
|
@@ -80,7 +80,7 @@ function playbackInterceptor({
|
|
|
80
80
|
socket,
|
|
81
81
|
options,
|
|
82
82
|
requestBodyString,
|
|
83
|
-
|
|
83
|
+
requestBodyIsUtf8Representable,
|
|
84
84
|
response,
|
|
85
85
|
interceptor,
|
|
86
86
|
}) {
|
|
@@ -178,10 +178,10 @@ function playbackInterceptor({
|
|
|
178
178
|
// will eventually be JSON stringified.
|
|
179
179
|
let responseBody = interceptor.body
|
|
180
180
|
|
|
181
|
-
// If the request was
|
|
182
|
-
//
|
|
183
|
-
// what the client will expect.
|
|
184
|
-
if (
|
|
181
|
+
// If the request was not UTF8-representable then we assume that the
|
|
182
|
+
// response won't be either. In that case we send the response as a Buffer
|
|
183
|
+
// object as that's what the client will expect.
|
|
184
|
+
if (!requestBodyIsUtf8Representable && typeof responseBody === 'string') {
|
|
185
185
|
// Try to create the buffer from the interceptor's body response as hex.
|
|
186
186
|
responseBody = Buffer.from(responseBody, 'hex')
|
|
187
187
|
|
package/lib/recorder.js
CHANGED
|
@@ -21,9 +21,9 @@ function getMethod(options) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function getBodyFromChunks(chunks, headers) {
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
24
|
+
// If we have headers and there is content-encoding it means that the body
|
|
25
|
+
// shouldn't be merged but instead persisted as an array of hex strings so
|
|
26
|
+
// that the response chunks can be mocked one by one.
|
|
27
27
|
if (headers && common.isContentEncoded(headers)) {
|
|
28
28
|
return {
|
|
29
29
|
body: chunks.map(chunk => chunk.toString('hex')),
|
|
@@ -32,30 +32,29 @@ function getBodyFromChunks(chunks, headers) {
|
|
|
32
32
|
|
|
33
33
|
const mergedBuffer = Buffer.concat(chunks)
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (isBinary) {
|
|
42
|
-
return {
|
|
43
|
-
body: mergedBuffer.toString('hex'),
|
|
44
|
-
isBinary: true,
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
35
|
+
// The merged buffer can be one of three things:
|
|
36
|
+
// 1. A UTF-8-representable string buffer which represents a JSON object.
|
|
37
|
+
// 2. A UTF-8-representable buffer which doesn't represent a JSON object.
|
|
38
|
+
// 3. A non-UTF-8-representable buffer which then has to be recorded as a hex string.
|
|
39
|
+
const isUtf8Representable = common.isUtf8Representable(mergedBuffer)
|
|
40
|
+
if (isUtf8Representable) {
|
|
47
41
|
const maybeStringifiedJson = mergedBuffer.toString('utf8')
|
|
48
42
|
try {
|
|
49
43
|
return {
|
|
44
|
+
isUtf8Representable,
|
|
50
45
|
body: JSON.parse(maybeStringifiedJson),
|
|
51
|
-
isBinary: false,
|
|
52
46
|
}
|
|
53
47
|
} catch (err) {
|
|
54
48
|
return {
|
|
49
|
+
isUtf8Representable,
|
|
55
50
|
body: maybeStringifiedJson,
|
|
56
|
-
isBinary: false,
|
|
57
51
|
}
|
|
58
52
|
}
|
|
53
|
+
} else {
|
|
54
|
+
return {
|
|
55
|
+
isUtf8Representable,
|
|
56
|
+
body: mergedBuffer.toString('hex'),
|
|
57
|
+
}
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
@@ -67,28 +66,26 @@ function generateRequestAndResponseObject({
|
|
|
67
66
|
dataChunks,
|
|
68
67
|
reqheaders,
|
|
69
68
|
}) {
|
|
70
|
-
const
|
|
69
|
+
const { body, isUtf8Representable } = getBodyFromChunks(
|
|
70
|
+
dataChunks,
|
|
71
|
+
res.headers
|
|
72
|
+
)
|
|
71
73
|
options.path = req.path
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
return {
|
|
74
76
|
scope: getScope(options),
|
|
75
77
|
method: getMethod(options),
|
|
76
78
|
path: options.path,
|
|
79
|
+
// Is it deliberate that `getBodyFromChunks()` is called a second time?
|
|
77
80
|
body: getBodyFromChunks(bodyChunks).body,
|
|
78
81
|
status: res.statusCode,
|
|
79
|
-
response:
|
|
82
|
+
response: body,
|
|
80
83
|
rawHeaders: res.rawHeaders,
|
|
84
|
+
reqheaders: reqheaders || undefined,
|
|
85
|
+
// When content-encoding is enabled, isUtf8Representable is `undefined`,
|
|
86
|
+
// so we explicitly check for `false`.
|
|
87
|
+
responseIsBinary: isUtf8Representable === false,
|
|
81
88
|
}
|
|
82
|
-
|
|
83
|
-
if (reqheaders) {
|
|
84
|
-
nockDef.reqheaders = reqheaders
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (response.isBinary) {
|
|
88
|
-
nockDef.responseIsBinary = true
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return nockDef
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
function generateRequestAndResponse({
|
package/lib/scope.js
CHANGED
|
@@ -347,11 +347,12 @@ function define(nockDefs) {
|
|
|
347
347
|
body = undefined
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
//
|
|
351
|
-
//
|
|
350
|
+
// Response is not always JSON as it could be a string or binary data or
|
|
351
|
+
// even an array of binary buffers (e.g. when content is encoded).
|
|
352
352
|
let response
|
|
353
353
|
if (!nockDef.response) {
|
|
354
354
|
response = ''
|
|
355
|
+
// TODO: Rename `responseIsBinary` to `reponseIsUtf8Representable`.
|
|
355
356
|
} else if (nockDef.responseIsBinary) {
|
|
356
357
|
response = Buffer.from(nockDef.response, 'hex')
|
|
357
358
|
} else {
|
package/lib/socket.js
CHANGED
|
@@ -12,8 +12,10 @@ module.exports = class Socket extends EventEmitter {
|
|
|
12
12
|
this.authorized = true
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
this.bufferSize = 0
|
|
15
16
|
this.writable = true
|
|
16
17
|
this.readable = true
|
|
18
|
+
this.pending = false
|
|
17
19
|
this.destroyed = false
|
|
18
20
|
this.connecting = false
|
|
19
21
|
|
|
@@ -23,13 +25,27 @@ module.exports = class Socket extends EventEmitter {
|
|
|
23
25
|
this.totalDelayMs = 0
|
|
24
26
|
// Maximum allowed delay. Null means unlimited.
|
|
25
27
|
this.timeoutMs = null
|
|
28
|
+
|
|
29
|
+
const ipv6 = options.family === 6
|
|
30
|
+
this.remoteFamily = ipv6 ? 'IPv6' : 'IPv4'
|
|
31
|
+
this.localAddress = this.remoteAddress = ipv6 ? '::1' : '127.0.0.1'
|
|
32
|
+
this.localPort = this.remotePort = parseInt(options.port)
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
setNoDelay() {}
|
|
29
36
|
setKeepAlive() {}
|
|
30
37
|
resume() {}
|
|
38
|
+
ref() {}
|
|
31
39
|
unref() {}
|
|
32
40
|
|
|
41
|
+
address() {
|
|
42
|
+
return {
|
|
43
|
+
port: this.remotePort,
|
|
44
|
+
family: this.remoteFamily,
|
|
45
|
+
address: this.remoteAddress,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
33
49
|
setTimeout(timeoutMs, fn) {
|
|
34
50
|
this.timeoutMs = timeoutMs
|
|
35
51
|
if (fn) {
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"testing",
|
|
8
8
|
"isolation"
|
|
9
9
|
],
|
|
10
|
-
"version": "11.
|
|
10
|
+
"version": "11.7.0",
|
|
11
11
|
"author": "Pedro Teixeira <pedro.teixeira@gmail.com>",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
@@ -31,28 +31,30 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"assert-rejects": "^1.0.0",
|
|
34
|
+
"dirty-chai": "^2.0.1",
|
|
34
35
|
"dtslint": "^0.9.1",
|
|
35
36
|
"eslint": "^6.0.0",
|
|
36
37
|
"eslint-config-prettier": "^6.0.0",
|
|
37
38
|
"eslint-config-standard": "^14.0.0",
|
|
38
39
|
"eslint-plugin-import": "^2.16.0",
|
|
40
|
+
"eslint-plugin-mocha": "^6.2.0",
|
|
39
41
|
"eslint-plugin-node": "^10.0.0",
|
|
40
42
|
"eslint-plugin-promise": "^4.1.1",
|
|
41
43
|
"eslint-plugin-standard": "^4.0.0",
|
|
42
44
|
"got": "^9.6.0",
|
|
43
|
-
"hyperquest": "^2.1.3",
|
|
44
45
|
"isomorphic-fetch": "^2.2.0",
|
|
45
46
|
"lolex": "^5.0.0",
|
|
47
|
+
"mocha": "^6.2.2",
|
|
46
48
|
"needle": "^2.3.0",
|
|
47
49
|
"npm-run-all": "^4.1.5",
|
|
48
50
|
"nyc": "^14.0.0",
|
|
49
51
|
"prettier": "1.18.2",
|
|
50
52
|
"proxyquire": "^2.1.0",
|
|
51
53
|
"request": "^2.83.0",
|
|
52
|
-
"restify-clients": "^2.2.0",
|
|
53
54
|
"rimraf": "^3.0.0",
|
|
54
55
|
"semantic-release": "^16.0.0-beta.22",
|
|
55
|
-
"sinon": "^7.
|
|
56
|
+
"sinon": "^7.5.0",
|
|
57
|
+
"sinon-chai": "^3.3.0",
|
|
56
58
|
"superagent": "^5.0.2",
|
|
57
59
|
"tap": "^14.0.0"
|
|
58
60
|
},
|
|
@@ -62,6 +64,7 @@
|
|
|
62
64
|
"test": "npm run -s unit",
|
|
63
65
|
"posttest": "npm run -s prettier:check",
|
|
64
66
|
"coverage": "tap --coverage-report=html && open coverage/lcov-report/index.html",
|
|
67
|
+
"mocha": "nyc mocha $(grep -lr '^\\s*it(' tests)",
|
|
65
68
|
"lint": "eslint \"**/*.js\"",
|
|
66
69
|
"prettier": "prettier --write \"**/*.@(js|json|md|ts|yml)\"",
|
|
67
70
|
"prettier:check": "prettier --check \"**/*.@(js|json|md|ts|yml)\"",
|