nock 11.5.0 → 11.7.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.
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)
@@ -995,6 +996,14 @@ You can cleanup all the prepared mocks (could be useful to cleanup some state af
995
996
  nock.cleanAll()
996
997
  ```
997
998
 
999
+ ### .abortPendingRequests()
1000
+
1001
+ You can abort all current pending request like this:
1002
+
1003
+ ```js
1004
+ nock.abortPendingRequests()
1005
+ ```
1006
+
998
1007
  ### .persist()
999
1008
 
1000
1009
  You can make all the interceptors for a scope persist by calling `.persist()` on it:
package/index.js CHANGED
@@ -12,6 +12,7 @@ const {
12
12
  disableNetConnect,
13
13
  enableNetConnect,
14
14
  removeAll,
15
+ abortPendingRequests,
15
16
  } = require('./lib/intercept')
16
17
  const recorder = require('./lib/recorder')
17
18
  const { Scope, load, loadDefs, define } = require('./lib/scope')
@@ -28,13 +29,14 @@ Object.assign(module.exports, {
28
29
  disableNetConnect,
29
30
  enableNetConnect,
30
31
  // TODO-12.x Historically `nock.cleanAll()` has returned the nock global.
31
- // The other global methods do noto do this, so it's not clear this was
32
+ // The other global methods do not do this, so it's not clear this was
32
33
  // deliberate or is even helpful. This shim is included for backward
33
34
  // compatibility and shoulud be replaced with an alias to `removeAll()`.
34
35
  cleanAll() {
35
36
  removeAll()
36
37
  return module.exports
37
38
  },
39
+ abortPendingRequests,
38
40
  load,
39
41
  loadDefs,
40
42
  define,
package/lib/back.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const assert = require('assert')
3
4
  const _ = require('lodash')
4
5
  const recorder = require('./recorder')
5
6
  const {
@@ -12,7 +13,6 @@ const { loadDefs, define } = require('./scope')
12
13
 
13
14
  const { format } = require('util')
14
15
  const path = require('path')
15
- const { expect } = require('chai')
16
16
  const debug = require('debug')('nock.back')
17
17
 
18
18
  let _mode = null
@@ -61,6 +61,7 @@ function Back(fixtureName, options, nockedFn) {
61
61
  )
62
62
  }
63
63
 
64
+ // TODO-12.x: Replace with `typeof fixtureName === 'string'`.
64
65
  if (!_.isString(fixtureName)) {
65
66
  throw new Error('Parameter fixtureName must be a string')
66
67
  }
@@ -70,7 +71,7 @@ function Back(fixtureName, options, nockedFn) {
70
71
  } else if (arguments.length === 2) {
71
72
  // If 2nd parameter is a function then `options` has been omitted
72
73
  // otherwise `options` haven't been omitted but `nockedFn` was.
73
- if (_.isFunction(options)) {
74
+ if (typeof options === 'function') {
74
75
  nockedFn = options
75
76
  options = {}
76
77
  }
@@ -88,7 +89,7 @@ function Back(fixtureName, options, nockedFn) {
88
89
  debug('context:', context)
89
90
 
90
91
  // If nockedFn is a function then invoke it, otherwise return a promise resolving to nockDone.
91
- if (_.isFunction(nockedFn)) {
92
+ if (typeof nockedFn === 'function') {
92
93
  nockedFn.call(context, nockDone)
93
94
  } else {
94
95
  return Promise.resolve({ nockDone, context })
@@ -244,16 +245,19 @@ function fixtureExists(fixture) {
244
245
  }
245
246
 
246
247
  function assertScopes(scopes, fixture) {
247
- scopes.forEach(function(scope) {
248
- expect(scope.isDone()).to.be.equal(
249
- true,
248
+ const pending = scopes
249
+ .filter(scope => !scope.isDone())
250
+ .map(scope => scope.pendingMocks())
251
+
252
+ if (pending.length) {
253
+ assert.fail(
250
254
  format(
251
255
  '%j was not used, consider removing %s to rerecord fixture',
252
- scope.pendingMocks(),
256
+ [].concat(...pending),
253
257
  fixture
254
258
  )
255
259
  )
256
- })
260
+ }
257
261
  }
258
262
 
259
263
  const Modes = {
package/lib/common.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const _ = require('lodash')
4
4
  const debug = require('debug')('nock.common')
5
5
  const url = require('url')
6
+ const timers = require('timers')
6
7
 
7
8
  /**
8
9
  * Normalizes the request options so that it always has `host` property.
@@ -37,23 +38,16 @@ function normalizeRequestOptions(options) {
37
38
  }
38
39
 
39
40
  /**
40
- * Returns false if the data contained in buffer can be reconstructed
41
+ * Returns true if the data contained in buffer can be reconstructed
41
42
  * from its utf8 representation.
42
43
  *
43
- * TODO: Reverse the semantics of this method and refactor calling code
44
- * accordingly. We've inadvertently gotten it flipped.
45
- *
46
44
  * @param {Object} buffer - a Buffer object
47
45
  * @returns {boolean}
48
46
  */
49
47
  function isUtf8Representable(buffer) {
50
- if (!Buffer.isBuffer(buffer)) {
51
- return false
52
- }
53
-
54
48
  const utfEncodedBuffer = buffer.toString('utf8')
55
49
  const reconstructedBuffer = Buffer.from(utfEncodedBuffer, 'utf8')
56
- return !reconstructedBuffer.equals(buffer)
50
+ return reconstructedBuffer.equals(buffer)
57
51
  }
58
52
 
59
53
  // Array where all information about all the overridden requests are held.
@@ -176,6 +170,7 @@ function stringifyRequest(options, body) {
176
170
 
177
171
  function isContentEncoded(headers) {
178
172
  const contentEncoding = headers['content-encoding']
173
+ // TODO-12.x: Replace with `typeof contentEncoding === 'string'`.
179
174
  return _.isString(contentEncoding) && contentEncoding !== ''
180
175
  }
181
176
 
@@ -365,6 +360,7 @@ function deleteHeadersField(headers, fieldNameToDelete) {
365
360
  throw Error('headers must be an object')
366
361
  }
367
362
 
363
+ // TODO-12.x: Replace with `typeof fieldNameToDelete !== 'string'`.
368
364
  if (!_.isString(fieldNameToDelete)) {
369
365
  throw Error('field name must be a string')
370
366
  }
@@ -446,6 +442,7 @@ function formatQueryValue(key, value, stringFormattingFn) {
446
442
  case value === undefined:
447
443
  value = ''
448
444
  break
445
+ // TODO-12.x: Replace with `typeof value === 'string'`.
449
446
  case _.isString(value):
450
447
  if (stringFormattingFn) {
451
448
  value = stringFormattingFn(value)
@@ -459,7 +456,7 @@ function formatQueryValue(key, value, stringFormattingFn) {
459
456
  })
460
457
  break
461
458
  }
462
- case _.isObject(value): {
459
+ case typeof value === 'object': {
463
460
  value = Object.entries(value).reduce(function(acc, [subKey, subVal]) {
464
461
  const subPair = formatQueryValue(subKey, subVal, stringFormattingFn)
465
462
  acc[subPair[0]] = subPair[1]
@@ -479,7 +476,7 @@ function isStream(obj) {
479
476
  obj &&
480
477
  typeof obj !== 'string' &&
481
478
  !Buffer.isBuffer(obj) &&
482
- _.isFunction(obj.setEncoding)
479
+ typeof obj.setEncoding === 'function'
483
480
  )
484
481
  }
485
482
 
@@ -593,6 +590,32 @@ function deepEqual(expected, actual) {
593
590
  return expected === actual
594
591
  }
595
592
 
593
+ const timeouts = []
594
+ const intervals = []
595
+ const immediates = []
596
+
597
+ const wrapTimer = (timer, ids) => (...args) => {
598
+ const id = timer(...args)
599
+ ids.push(id)
600
+ return id
601
+ }
602
+
603
+ const setTimeout = wrapTimer(timers.setTimeout, timeouts)
604
+ const setInterval = wrapTimer(timers.setInterval, intervals)
605
+ const setImmediate = wrapTimer(timers.setImmediate, immediates)
606
+
607
+ function clearTimer(clear, ids) {
608
+ while (ids.length) {
609
+ clear(ids.shift())
610
+ }
611
+ }
612
+
613
+ function removeAllTimers() {
614
+ clearTimer(clearTimeout, timeouts)
615
+ clearTimer(clearInterval, intervals)
616
+ clearTimer(clearImmediate, immediates)
617
+ }
618
+
596
619
  exports.normalizeClientRequestArgs = normalizeClientRequestArgs
597
620
  exports.normalizeRequestOptions = normalizeRequestOptions
598
621
  exports.normalizeOrigin = normalizeOrigin
@@ -615,3 +638,7 @@ exports.matchStringOrRegexp = matchStringOrRegexp
615
638
  exports.formatQueryValue = formatQueryValue
616
639
  exports.isStream = isStream
617
640
  exports.dataEqual = dataEqual
641
+ exports.setTimeout = setTimeout
642
+ exports.setInterval = setInterval
643
+ exports.setImmediate = setImmediate
644
+ exports.removeAllTimers = removeAllTimers
@@ -34,7 +34,7 @@ module.exports = class DelayedBody extends Transform {
34
34
 
35
35
  // TODO: This would be more readable if the stream case were moved into
36
36
  // the `if` statement above.
37
- setTimeout(function() {
37
+ common.setTimeout(function() {
38
38
  if (common.isStream(body) && !ended) {
39
39
  body.once('end', function() {
40
40
  self.end(data)
package/lib/intercept.js CHANGED
@@ -11,7 +11,6 @@ const http = require('http')
11
11
  const _ = require('lodash')
12
12
  const debug = require('debug')('nock.intercept')
13
13
  const globalEmitter = require('./global_emitter')
14
- const timers = require('timers')
15
14
 
16
15
  /**
17
16
  * @name NetConnectNotAllowedError
@@ -53,9 +52,10 @@ let allowNetConnect
53
52
  * nock.enableNetConnect(/(google|amazon)/);
54
53
  */
55
54
  function enableNetConnect(matcher) {
55
+ // TODO-12.x: Replace with `typeof matcher === 'string'`.
56
56
  if (_.isString(matcher)) {
57
57
  allowNetConnect = new RegExp(matcher)
58
- } else if (_.isObject(matcher) && _.isFunction(matcher.test)) {
58
+ } else if (matcher instanceof RegExp) {
59
59
  allowNetConnect = matcher
60
60
  } else {
61
61
  allowNetConnect = /.*/
@@ -160,7 +160,9 @@ function interceptorsFor(options) {
160
160
 
161
161
  // Keep the filtered scope (its key) to signal the rest of the module
162
162
  // that this wasn't an exact but filtered match.
163
- interceptor.__nock_filteredScope = interceptor.__nock_scopeKey
163
+ interceptors.forEach(ic => {
164
+ ic.__nock_filteredScope = ic.__nock_scopeKey
165
+ })
164
166
  return interceptors
165
167
  }
166
168
  }
@@ -171,7 +173,7 @@ function interceptorsFor(options) {
171
173
  return [
172
174
  {
173
175
  options: { allowUnmocked: true },
174
- matchAddress() {
176
+ matchOrigin() {
175
177
  return false
176
178
  },
177
179
  },
@@ -293,7 +295,7 @@ function overrideClientRequest() {
293
295
  if (isOff() || isEnabledForNetConnect(options)) {
294
296
  originalClientRequest.apply(this, arguments)
295
297
  } else {
296
- timers.setImmediate(
298
+ common.setImmediate(
297
299
  function() {
298
300
  const error = new NetConnectNotAllowedError(
299
301
  options.host,
@@ -390,13 +392,12 @@ function activate() {
390
392
  const interceptors = interceptorsFor(options)
391
393
 
392
394
  if (isOn() && interceptors) {
393
- const matches = !!_.find(interceptors, function(interceptor) {
394
- return interceptor.matchAddress(options)
395
- })
396
-
397
- const allowUnmocked = !!_.find(interceptors, function(interceptor) {
398
- return interceptor.options.allowUnmocked
399
- })
395
+ const matches = interceptors.some(interceptor =>
396
+ interceptor.matchOrigin(options)
397
+ )
398
+ const allowUnmocked = interceptors.some(
399
+ interceptor => interceptor.options.allowUnmocked
400
+ )
400
401
 
401
402
  if (!matches && allowUnmocked) {
402
403
  let req
@@ -444,4 +445,5 @@ module.exports = {
444
445
  disableNetConnect,
445
446
  overrideClientRequest,
446
447
  restoreOverriddenClientRequest,
448
+ abortPendingRequests: common.removeAllTimers,
447
449
  }
@@ -8,7 +8,6 @@ const {
8
8
  } = require('http')
9
9
  const { request: originalHttpsRequest } = require('https')
10
10
  const propagate = require('propagate')
11
- const timers = require('timers')
12
11
  const common = require('./common')
13
12
  const globalEmitter = require('./global_emitter')
14
13
  const Socket = require('./socket')
@@ -31,7 +30,7 @@ class InterceptedRequestRouter {
31
30
  }
32
31
  this.interceptors = interceptors
33
32
 
34
- this.socket = new Socket({ proto: options.proto })
33
+ this.socket = new Socket(options)
35
34
  this.response = new IncomingMessage(this.socket)
36
35
  this.playbackStarted = false
37
36
  this.requestBodyBuffers = []
@@ -74,7 +73,7 @@ class InterceptedRequestRouter {
74
73
 
75
74
  // https://github.com/nock/nock/issues/256
76
75
  if (options.headers.expect === '100-continue') {
77
- timers.setImmediate(() => {
76
+ common.setImmediate(() => {
78
77
  debug('continue')
79
78
  req.emit('continue')
80
79
  })
@@ -114,6 +113,10 @@ class InterceptedRequestRouter {
114
113
  }
115
114
  this.requestBodyBuffers.push(buffer)
116
115
  }
116
+ // can't use instanceof Function because some test runners
117
+ // run tests in vm.runInNewContext where Function is not same
118
+ // as that in the current context
119
+ // https://github.com/nock/nock/pull/1754#issuecomment-571531407
117
120
  if (typeof callback === 'function') {
118
121
  callback()
119
122
  }
@@ -121,7 +124,7 @@ class InterceptedRequestRouter {
121
124
  this.emitError(new Error('Request aborted'))
122
125
  }
123
126
 
124
- timers.setImmediate(function() {
127
+ common.setImmediate(function() {
125
128
  req.emit('drain')
126
129
  })
127
130
 
@@ -232,8 +235,9 @@ class InterceptedRequestRouter {
232
235
  // Re-update `options` with the current value of `req.path` because badly
233
236
  // behaving agents like superagent like to change `req.path` mid-flight.
234
237
  path: req.path,
235
- // similarly, node-http-proxy will modify headers in flight, so we have
238
+ // Similarly, node-http-proxy will modify headers in flight, so we have
236
239
  // to put the headers back into options.
240
+ // https://github.com/nock/nock/pull/1484
237
241
  headers: req.getHeaders(),
238
242
  // Fixes https://github.com/nock/nock/issues/976
239
243
  protocol: `${options.proto}:`,
@@ -246,11 +250,11 @@ class InterceptedRequestRouter {
246
250
  const requestBodyBuffer = Buffer.concat(this.requestBodyBuffers)
247
251
  // When request body is a binary buffer we internally use in its hexadecimal
248
252
  // representation.
249
- const isBinaryRequestBodyBuffer = common.isUtf8Representable(
253
+ const requestBodyIsUtf8Representable = common.isUtf8Representable(
250
254
  requestBodyBuffer
251
255
  )
252
256
  const requestBodyString = requestBodyBuffer.toString(
253
- isBinaryRequestBodyBuffer ? 'hex' : 'utf8'
257
+ requestBodyIsUtf8Representable ? 'utf8' : 'hex'
254
258
  )
255
259
 
256
260
  const matchedInterceptor = interceptors.find(i =>
@@ -265,7 +269,7 @@ class InterceptedRequestRouter {
265
269
  socket,
266
270
  options,
267
271
  requestBodyString,
268
- isBinaryRequestBodyBuffer,
272
+ requestBodyIsUtf8Representable,
269
273
  response,
270
274
  interceptor: matchedInterceptor,
271
275
  })
@@ -110,7 +110,7 @@ module.exports = class Interceptor {
110
110
 
111
111
  reply(statusCode, body, rawHeaders) {
112
112
  // support the format of only passing in a callback
113
- if (_.isFunction(statusCode)) {
113
+ if (typeof statusCode === 'function') {
114
114
  if (arguments.length > 1) {
115
115
  // It's not very Javascript-y to throw an error for extra args to a function, but because
116
116
  // of legacy behavior, this error was added to reduce confusion for those migrating.
@@ -126,7 +126,7 @@ module.exports = class Interceptor {
126
126
  }
127
127
 
128
128
  this.statusCode = statusCode || 200
129
- if (_.isFunction(body)) {
129
+ if (typeof body === 'function') {
130
130
  this.replyFunction = body
131
131
  body = null
132
132
  }
@@ -200,6 +200,8 @@ module.exports = class Interceptor {
200
200
  const reqHeader = this.reqheaders[key]
201
201
  let header = options.headers[key]
202
202
 
203
+ // https://github.com/nock/nock/issues/399
204
+ // https://github.com/nock/nock/issues/822
203
205
  if (header && typeof header !== 'string' && header.toString) {
204
206
  header = header.toString()
205
207
  }
@@ -213,7 +215,7 @@ module.exports = class Interceptor {
213
215
  }
214
216
 
215
217
  if (reqHeader !== undefined && header !== undefined) {
216
- if (_.isFunction(reqHeader)) {
218
+ if (typeof reqHeader === 'function') {
217
219
  return reqHeader(header)
218
220
  } else if (common.matchStringOrRegexp(header, reqHeader)) {
219
221
  return true
@@ -352,9 +354,9 @@ module.exports = class Interceptor {
352
354
  * Return true when the interceptor's method, protocol, host, port, and path
353
355
  * match the provided options.
354
356
  */
355
- matchAddress(options) {
356
- const isRegex = _.isRegExp(this.path)
357
- const isRegexBasePath = _.isRegExp(this.scope.basePath)
357
+ matchOrigin(options) {
358
+ const isRegex = this.path instanceof RegExp
359
+ const isRegexBasePath = this.scope.basePath instanceof RegExp
358
360
 
359
361
  const method = (options.method || 'GET').toUpperCase()
360
362
  let { path } = options
@@ -395,7 +397,7 @@ module.exports = class Interceptor {
395
397
  debug('Interceptor queries: %j', this.queries)
396
398
  debug(' Request queries: %j', reqQueries)
397
399
 
398
- if (_.isFunction(this.queries)) {
400
+ if (typeof this.queries === 'function') {
399
401
  return this.queries(reqQueries)
400
402
  }
401
403
 
@@ -456,7 +458,7 @@ module.exports = class Interceptor {
456
458
  return this
457
459
  }
458
460
 
459
- if (_.isFunction(queries)) {
461
+ if (typeof queries === 'function') {
460
462
  this.queries = queries
461
463
  return this
462
464
  }
@@ -553,7 +555,7 @@ module.exports = class Interceptor {
553
555
  if (_.isNumber(opts)) {
554
556
  headDelay = opts
555
557
  bodyDelay = 0
556
- } else if (_.isObject(opts)) {
558
+ } else if (typeof opts === 'object') {
557
559
  headDelay = opts.head || 0
558
560
  bodyDelay = opts.body || 0
559
561
  } else {
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
- if (common.isUtf8Representable(spec)) {
15
- spec = spec.toString('hex')
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 = (
@@ -59,12 +56,7 @@ module.exports = function matchBody(options, spec, body) {
59
56
  // Because the nature of URL encoding, all the values in the body have been cast to strings.
60
57
  // dataEqual does strict checking so we we have to cast the non-regexp values in the spec too.
61
58
  if (isUrlencoded) {
62
- spec = mapValuesDeep(spec, function(val) {
63
- if (_.isRegExp(val)) {
64
- return val
65
- }
66
- return `${val}`
67
- })
59
+ spec = mapValuesDeep(spec, val => (val instanceof RegExp ? val : `${val}`))
68
60
  }
69
61
 
70
62
  return common.dataEqual(spec, body)
@@ -76,14 +68,10 @@ module.exports = function matchBody(options, spec, body) {
76
68
  */
77
69
  function mapValuesDeep(obj, cb) {
78
70
  if (Array.isArray(obj)) {
79
- return obj.map(function(v) {
80
- return mapValuesDeep(v, cb)
81
- })
71
+ return obj.map(v => mapValuesDeep(v, cb))
82
72
  }
83
73
  if (_.isPlainObject(obj)) {
84
- return _.mapValues(obj, function(v) {
85
- return mapValuesDeep(v, cb)
86
- })
74
+ return _.mapValues(obj, v => mapValuesDeep(v, cb))
87
75
  }
88
76
  return cb(obj)
89
77
  }
@@ -1,10 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const util = require('util')
4
- const timers = require('timers')
5
4
  const zlib = require('zlib')
6
5
  const debug = require('debug')('nock.playback_interceptor')
7
- const _ = require('lodash')
8
6
  const common = require('./common')
9
7
  const DelayedBody = require('./delayed_body')
10
8
 
@@ -81,7 +79,7 @@ function playbackInterceptor({
81
79
  socket,
82
80
  options,
83
81
  requestBodyString,
84
- isBinaryRequestBodyBuffer,
82
+ requestBodyIsUtf8Representable,
85
83
  response,
86
84
  interceptor,
87
85
  }) {
@@ -101,12 +99,12 @@ function playbackInterceptor({
101
99
  interceptor.markConsumed()
102
100
 
103
101
  let error
104
- if (_.isObject(interceptor.errorMessage)) {
102
+ if (typeof interceptor.errorMessage === 'object') {
105
103
  error = interceptor.errorMessage
106
104
  } else {
107
105
  error = new Error(interceptor.errorMessage)
108
106
  }
109
- timers.setTimeout(() => emitError(error), interceptor.getTotalDelay())
107
+ common.setTimeout(() => emitError(error), interceptor.getTotalDelay())
110
108
  return
111
109
  }
112
110
 
@@ -179,10 +177,10 @@ function playbackInterceptor({
179
177
  // will eventually be JSON stringified.
180
178
  let responseBody = interceptor.body
181
179
 
182
- // If the request was binary then we assume that the response will be binary
183
- // as well. In that case we send the response as a Buffer object as that's
184
- // what the client will expect.
185
- if (isBinaryRequestBodyBuffer && typeof responseBody === 'string') {
180
+ // If the request was not UTF8-representable then we assume that the
181
+ // response won't be either. In that case we send the response as a Buffer
182
+ // object as that's what the client will expect.
183
+ if (!requestBodyIsUtf8Representable && typeof responseBody === 'string') {
186
184
  // Try to create the buffer from the interceptor's body response as hex.
187
185
  responseBody = Buffer.from(responseBody, 'hex')
188
186
 
@@ -311,13 +309,13 @@ function playbackInterceptor({
311
309
  }
312
310
 
313
311
  // Stream the response chunks one at a time.
314
- timers.setImmediate(function emitChunk() {
312
+ common.setImmediate(function emitChunk() {
315
313
  const chunk = responseBuffers.shift()
316
314
 
317
315
  if (chunk) {
318
316
  debug('emitting response chunk')
319
317
  response.push(chunk)
320
- timers.setImmediate(emitChunk)
318
+ common.setImmediate(emitChunk)
321
319
  } else {
322
320
  debug('ending response stream')
323
321
  response.push(null)
@@ -338,7 +336,7 @@ function playbackInterceptor({
338
336
  interceptor.delayConnectionInMs > 0
339
337
  ) {
340
338
  socket.applyDelay(interceptor.delayConnectionInMs)
341
- setTimeout(respond, interceptor.delayConnectionInMs)
339
+ common.setTimeout(respond, interceptor.delayConnectionInMs)
342
340
  } else {
343
341
  respond()
344
342
  }
package/lib/recorder.js CHANGED
@@ -21,9 +21,9 @@ function getMethod(options) {
21
21
  }
22
22
 
23
23
  function getBodyFromChunks(chunks, headers) {
24
- // If we have headers and there is content-encoding it means that
25
- // the body shouldn't be merged but instead persisted as an array
26
- // of hex strings so that the responses can be mocked one by one.
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
- // The merged buffer can be one of three things:
36
- // 1. A binary buffer which then has to be recorded as a hex string.
37
- // 2. A string buffer which represents a JSON object.
38
- // 3. A string buffer which doesn't represent a JSON object.
39
-
40
- const isBinary = common.isUtf8Representable(mergedBuffer)
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 response = getBodyFromChunks(dataChunks, res.headers)
69
+ const { body, isUtf8Representable } = getBodyFromChunks(
70
+ dataChunks,
71
+ res.headers
72
+ )
71
73
  options.path = req.path
72
74
 
73
- const nockDef = {
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: response.body,
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
- // 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)
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.5.0",
10
+ "version": "11.7.2",
11
11
  "author": "Pedro Teixeira <pedro.teixeira@gmail.com>",
12
12
  "repository": {
13
13
  "type": "git",
@@ -22,7 +22,6 @@
22
22
  "main": "./index.js",
23
23
  "types": "types",
24
24
  "dependencies": {
25
- "chai": "^4.1.2",
26
25
  "debug": "^4.1.0",
27
26
  "json-stringify-safe": "^5.0.1",
28
27
  "lodash": "^4.17.13",
@@ -31,28 +30,29 @@
31
30
  },
32
31
  "devDependencies": {
33
32
  "assert-rejects": "^1.0.0",
34
- "dtslint": "^0.9.1",
33
+ "chai": "^4.1.2",
34
+ "dirty-chai": "^2.0.1",
35
+ "dtslint": "^2.0.2",
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",
39
- "eslint-plugin-node": "^10.0.0",
40
+ "eslint-plugin-mocha": "^6.2.0",
41
+ "eslint-plugin-node": "^11.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
- "isomorphic-fetch": "^2.2.0",
45
45
  "lolex": "^5.0.0",
46
- "needle": "^2.3.0",
46
+ "mocha": "^6.2.2",
47
47
  "npm-run-all": "^4.1.5",
48
- "nyc": "^14.0.0",
49
- "prettier": "1.18.2",
48
+ "nyc": "^15.0.0",
49
+ "prettier": "1.19.0",
50
50
  "proxyquire": "^2.1.0",
51
51
  "request": "^2.83.0",
52
- "restify-clients": "^2.2.0",
53
52
  "rimraf": "^3.0.0",
54
53
  "semantic-release": "^16.0.0-beta.22",
55
- "sinon": "^7.3.1",
54
+ "sinon": "^8.0.0",
55
+ "sinon-chai": "^3.3.0",
56
56
  "superagent": "^5.0.2",
57
57
  "tap": "^14.0.0"
58
58
  },
@@ -62,6 +62,7 @@
62
62
  "test": "npm run -s unit",
63
63
  "posttest": "npm run -s prettier:check",
64
64
  "coverage": "tap --coverage-report=html && open coverage/lcov-report/index.html",
65
+ "mocha": "nyc mocha $(grep -lr '^\\s*it(' tests)",
65
66
  "lint": "eslint \"**/*.js\"",
66
67
  "prettier": "prettier --write \"**/*.@(js|json|md|ts|yml)\"",
67
68
  "prettier:check": "prettier --check \"**/*.@(js|json|md|ts|yml)\"",
package/types/index.d.ts CHANGED
@@ -26,6 +26,7 @@ declare namespace nock {
26
26
  function loadDefs(path: string): Definition[]
27
27
  function define(defs: Definition[]): Scope[]
28
28
  function restore(): void
29
+ function abortPendingRequests(): void
29
30
 
30
31
  let back: Back
31
32
  let emitter: NodeJS.EventEmitter
@@ -243,6 +244,7 @@ declare namespace nock {
243
244
  type BackMode = 'wild' | 'dryrun' | 'record' | 'lockdown'
244
245
 
245
246
  interface Back {
247
+ currentMode: BackMode
246
248
  fixtures: string
247
249
  setMode(mode: BackMode): void
248
250