nock 13.1.4 → 13.2.3

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
@@ -1323,6 +1323,18 @@ const interceptor = nock('http://example.org').get('somePath')
1323
1323
  nock.removeInterceptor(interceptor)
1324
1324
  ```
1325
1325
 
1326
+ **Note** `.reply(...)` method returns Scope, not Interceptor, and so it is not a valid argument for `nock.removeInterceptor`. So if your method chain ends with `.reply` to be used with `nock.removeInterceptor` the chain need to be break in between:
1327
+
1328
+ ```js
1329
+ // this will NOT work
1330
+ const interceptor = nock('http://example.org').get('somePath').reply(200, 'OK')
1331
+ nock.removeInterceptor(interceptor)
1332
+ // this is how it should be
1333
+ const interceptor = nock('http://example.org').get('somePath')
1334
+ interceptor.reply(200, 'OK')
1335
+ nock.removeInterceptor(interceptor)
1336
+ ```
1337
+
1326
1338
  ## Events
1327
1339
 
1328
1340
  A scope emits the following events:
@@ -1459,6 +1471,8 @@ To set the mode call `nockBack.setMode(mode)` or run the tests with the `NOCK_BA
1459
1471
 
1460
1472
  - record: use recorded nocks, record new nocks
1461
1473
 
1474
+ - update: remove recorded nocks, record nocks
1475
+
1462
1476
  - lockdown: use recorded nocks, disables all http calls even when not nocked, doesn't record
1463
1477
 
1464
1478
  ## Common issues
@@ -1591,6 +1605,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/all-contri
1591
1605
  <td align="center"><a href="https://github.com/benrki"><img src="https://avatars0.githubusercontent.com/u/4446950?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Ki</b></sub></a><br /><a href="#financial-benrki" title="Financial">💵</a></td>
1592
1606
  <td align="center"><a href="http://chadf.ca"><img src="https://avatars2.githubusercontent.com/u/3250463?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chad Fawcett</b></sub></a><br /><a href="#financial-chadfawcett" title="Financial">💵</a></td>
1593
1607
  <td align="center"><a href="http://www.laurencemyers.com.au"><img src="https://avatars.githubusercontent.com/u/6336048?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Laurence Dougal Myers</b></sub></a><br /><a href="https://github.com/nock/nock/commits?author=laurence-myers" title="Code">💻</a></td>
1608
+ <td align="center"><a href="https://github.com/Beretta1979"><img src="https://avatars.githubusercontent.com/u/10073962?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sébastien Van Bruaene</b></sub></a><br /><a href="https://github.com/nock/nock/commits?author=Beretta1979" title="Code">💻</a> <a href="https://github.com/nock/nock/commits?author=Beretta1979" title="Tests">⚠️</a></td>
1594
1609
  </tr>
1595
1610
  </table>
1596
1611
 
package/lib/back.js CHANGED
@@ -175,6 +175,47 @@ const record = {
175
175
  },
176
176
  }
177
177
 
178
+ const update = {
179
+ setup: function () {
180
+ recorder.restore()
181
+ recorder.clear()
182
+ cleanAll()
183
+ activate()
184
+ disableNetConnect()
185
+ },
186
+
187
+ start: function (fixture, options) {
188
+ if (!fs) {
189
+ throw new Error('no fs')
190
+ }
191
+ const context = removeFixture(fixture)
192
+ recorder.record({
193
+ dont_print: true,
194
+ output_objects: true,
195
+ ...options.recorder,
196
+ })
197
+
198
+ context.isRecording = true
199
+
200
+ return context
201
+ },
202
+
203
+ finish: function (fixture, options, context) {
204
+ let outputs = recorder.outputs()
205
+
206
+ if (typeof options.afterRecord === 'function') {
207
+ outputs = options.afterRecord(outputs)
208
+ }
209
+
210
+ outputs =
211
+ typeof outputs === 'string' ? outputs : JSON.stringify(outputs, null, 4)
212
+ debug('recorder outputs:', outputs)
213
+
214
+ fs.mkdirSync(path.dirname(fixture), { recursive: true })
215
+ fs.writeFileSync(fixture, outputs)
216
+ },
217
+ }
218
+
178
219
  const lockdown = {
179
220
  setup: function () {
180
221
  recorder.restore()
@@ -215,6 +256,20 @@ function load(fixture, options) {
215
256
  return context
216
257
  }
217
258
 
259
+ function removeFixture(fixture, options) {
260
+ const context = {
261
+ scopes: [],
262
+ assertScopesFinished: function () {},
263
+ }
264
+
265
+ if (fixture && fixtureExists(fixture)) {
266
+ /* istanbul ignore next - fs.unlinkSync is for node 10 support */
267
+ fs.rmSync ? fs.rmSync(fixture) : fs.unlinkSync(fixture)
268
+ }
269
+ context.isLoaded = false
270
+ return context
271
+ }
272
+
218
273
  function applyHook(scopes, fn) {
219
274
  if (!fn) {
220
275
  return
@@ -258,6 +313,8 @@ const Modes = {
258
313
 
259
314
  record, // use recorded nocks, record new nocks
260
315
 
316
+ update, // allow http calls, record all nocks, don't use recorded nocks
317
+
261
318
  lockdown, // use recorded nocks, disables all http calls even when not nocked, doesnt record
262
319
  }
263
320
 
package/lib/common.js CHANGED
@@ -194,7 +194,7 @@ function isJSONContent(headers) {
194
194
  *
195
195
  * Duplicates throw an error.
196
196
  */
197
- function headersFieldNamesToLowerCase(headers) {
197
+ function headersFieldNamesToLowerCase(headers, throwOnDuplicate) {
198
198
  if (!isPlainObject(headers)) {
199
199
  throw Error('Headers must be provided as an object')
200
200
  }
@@ -203,9 +203,15 @@ function headersFieldNamesToLowerCase(headers) {
203
203
  Object.entries(headers).forEach(([fieldName, fieldValue]) => {
204
204
  const key = fieldName.toLowerCase()
205
205
  if (lowerCaseHeaders[key] !== undefined) {
206
- throw Error(
207
- `Failed to convert header keys to lower case due to field name conflict: ${key}`
208
- )
206
+ if (throwOnDuplicate) {
207
+ throw Error(
208
+ `Failed to convert header keys to lower case due to field name conflict: ${key}`
209
+ )
210
+ } else {
211
+ debug(
212
+ `Duplicate header provided in request: ${key}. Only the last value can be matched.`
213
+ )
214
+ }
209
215
  }
210
216
  lowerCaseHeaders[key] = fieldValue
211
217
  })
@@ -547,7 +553,7 @@ function urlToOptions(url) {
547
553
  * Used for comparing decoded search parameters, request body JSON objects,
548
554
  * and URL decoded request form bodies.
549
555
  *
550
- * Performs a general recursive strict comparision with two caveats:
556
+ * Performs a general recursive strict comparison with two caveats:
551
557
  * - The expected data can use regexp to compare values
552
558
  * - JSON path notation and nested objects are considered equal
553
559
  */
@@ -651,11 +657,13 @@ const timeouts = []
651
657
  const intervals = []
652
658
  const immediates = []
653
659
 
654
- const wrapTimer = (timer, ids) => (...args) => {
655
- const id = timer(...args)
656
- ids.push(id)
657
- return id
658
- }
660
+ const wrapTimer =
661
+ (timer, ids) =>
662
+ (...args) => {
663
+ const id = timer(...args)
664
+ ids.push(id)
665
+ return id
666
+ }
659
667
 
660
668
  const setTimeout = wrapTimer(timers.setTimeout, timeouts)
661
669
  const setInterval = wrapTimer(timers.setInterval, intervals)
@@ -40,7 +40,10 @@ class InterceptedRequestRouter {
40
40
  // affecting the user so we use a clone of the object.
41
41
  ...options,
42
42
  // We use lower-case header field names throughout Nock.
43
- headers: common.headersFieldNamesToLowerCase(options.headers || {}),
43
+ headers: common.headersFieldNamesToLowerCase(
44
+ options.headers || {},
45
+ false
46
+ ),
44
47
  }
45
48
  this.interceptors = interceptors
46
49
 
@@ -48,8 +51,12 @@ class InterceptedRequestRouter {
48
51
 
49
52
  // support setting `timeout` using request `options`
50
53
  // https://nodejs.org/docs/latest-v12.x/api/http.html#http_http_request_url_options_callback
51
- if (options.timeout) {
52
- this.socket.setTimeout(options.timeout)
54
+ // any timeout in the request options override any timeout in the agent options.
55
+ // per https://github.com/nodejs/node/pull/21204
56
+ const timeout =
57
+ options.timeout || (options.agent && options.agent.options.timeout)
58
+ if (timeout) {
59
+ this.socket.setTimeout(timeout)
53
60
  }
54
61
 
55
62
  this.response = new IncomingMessage(this.socket)
@@ -279,9 +286,8 @@ class InterceptedRequestRouter {
279
286
  const requestBodyBuffer = Buffer.concat(this.requestBodyBuffers)
280
287
  // When request body is a binary buffer we internally use in its hexadecimal
281
288
  // representation.
282
- const requestBodyIsUtf8Representable = common.isUtf8Representable(
283
- requestBodyBuffer
284
- )
289
+ const requestBodyIsUtf8Representable =
290
+ common.isUtf8Representable(requestBodyBuffer)
285
291
  const requestBodyString = requestBodyBuffer.toString(
286
292
  requestBodyIsUtf8Representable ? 'utf8' : 'hex'
287
293
  )
@@ -66,7 +66,8 @@ module.exports = class Interceptor {
66
66
 
67
67
  // We use lower-case header field names throughout Nock.
68
68
  this.reqheaders = common.headersFieldNamesToLowerCase(
69
- scope.scopeOptions.reqheaders || {}
69
+ scope.scopeOptions.reqheaders || {},
70
+ true
70
71
  )
71
72
  this.badheaders = common.headersFieldsArrayToLowerCase(
72
73
  scope.scopeOptions.badheaders || []
@@ -155,7 +156,7 @@ module.exports = class Interceptor {
155
156
  )
156
157
 
157
158
  // If the content is not encoded we may need to transform the response body.
158
- // Otherwise we leave it as it is.
159
+ // Otherwise, we leave it as it is.
159
160
  if (
160
161
  body &&
161
162
  typeof body !== 'string' &&
@@ -173,10 +174,14 @@ module.exports = class Interceptor {
173
174
  // https://tools.ietf.org/html/rfc7231#section-3.1.1.5
174
175
  this.rawHeaders.push('Content-Type', 'application/json')
175
176
  }
177
+ }
176
178
 
177
- if (this.scope.contentLen) {
178
- // https://tools.ietf.org/html/rfc7230#section-3.3.2
179
+ if (this.scope.contentLen) {
180
+ // https://tools.ietf.org/html/rfc7230#section-3.3.2
181
+ if (typeof body === 'string') {
179
182
  this.rawHeaders.push('Content-Length', body.length)
183
+ } else if (Buffer.isBuffer(body)) {
184
+ this.rawHeaders.push('Content-Length', body.byteLength)
180
185
  }
181
186
  }
182
187
 
@@ -412,6 +417,12 @@ module.exports = class Interceptor {
412
417
  }
413
418
 
414
419
  matchHostName(options) {
420
+ const { basePath } = this.scope
421
+
422
+ if (basePath instanceof RegExp) {
423
+ return basePath.test(options.hostname)
424
+ }
425
+
415
426
  return options.hostname === this.scope.urlParts.hostname
416
427
  }
417
428
 
@@ -79,7 +79,7 @@ class ReadableBuffers extends stream.Readable {
79
79
  this.buffers = buffers
80
80
  }
81
81
 
82
- _read(size) {
82
+ _read(_size) {
83
83
  while (this.buffers.length) {
84
84
  if (!this.push(this.buffers.shift())) {
85
85
  return
@@ -315,7 +315,7 @@ function playbackInterceptor({
315
315
 
316
316
  // Calling `start` immediately could take the request all the way to the connection delay
317
317
  // during a single microtask execution. This setImmediate stalls the playback to ensure the
318
- // correct events are emitted first ('socket', 'finish') and any aborts in the in the queue or
318
+ // correct events are emitted first ('socket', 'finish') and any aborts in the queue or
319
319
  // called during a 'finish' listener can be called.
320
320
  common.setImmediate(() => {
321
321
  if (!common.isRequestDestroyed(req)) {
package/lib/recorder.js CHANGED
@@ -168,7 +168,7 @@ let currentRecordingId = 0
168
168
  const defaultRecordOptions = {
169
169
  dont_print: false,
170
170
  enable_reqheaders_recording: false,
171
- logging: console.log,
171
+ logging: console.log, // eslint-disable-line no-console
172
172
  output_objects: false,
173
173
  use_separator: true,
174
174
  }
package/package.json CHANGED
@@ -7,14 +7,14 @@
7
7
  "testing",
8
8
  "isolation"
9
9
  ],
10
- "version": "13.1.4",
10
+ "version": "13.2.3",
11
11
  "author": "Pedro Teixeira <pedro.teixeira@gmail.com>",
12
12
  "repository": {
13
13
  "type": "git",
14
14
  "url": "https://github.com/nock/nock.git"
15
15
  },
16
16
  "bugs": {
17
- "url": "http://github.com/nock/nock/issues"
17
+ "url": "https://github.com/nock/nock/issues"
18
18
  },
19
19
  "engines": {
20
20
  "node": ">= 10.13"
@@ -28,30 +28,29 @@
28
28
  "propagate": "^2.0.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@sinonjs/fake-timers": "^7.0.2",
31
+ "@definitelytyped/dtslint": "^0.0.103",
32
+ "@sinonjs/fake-timers": "^9.0.0",
32
33
  "assert-rejects": "^1.0.0",
33
34
  "chai": "^4.1.2",
34
35
  "dirty-chai": "^2.0.1",
35
- "dtslint": "^4.0.4",
36
- "eslint": "^7.3.1",
36
+ "eslint": "^8.8.0",
37
37
  "eslint-config-prettier": "^8.1.0",
38
- "eslint-config-standard": "^16.0.2",
38
+ "eslint-config-standard": "^17.0.0-0",
39
39
  "eslint-plugin-import": "^2.16.0",
40
- "eslint-plugin-mocha": "^8.0.0",
40
+ "eslint-plugin-mocha": "^10.0.3",
41
41
  "eslint-plugin-node": "^11.0.0",
42
- "eslint-plugin-promise": "^4.1.1",
43
- "eslint-plugin-standard": "^5.0.0",
42
+ "eslint-plugin-promise": "^6.0.0",
44
43
  "form-data": "^4.0.0",
45
44
  "got": "^11.3.0",
46
- "mocha": "^8.0.1",
45
+ "mocha": "^9.1.3",
47
46
  "npm-run-all": "^4.1.5",
48
47
  "nyc": "^15.0.0",
49
- "prettier": "2.2.1",
48
+ "prettier": "2.5.1",
50
49
  "proxyquire": "^2.1.0",
51
50
  "rimraf": "^3.0.0",
52
- "semantic-release": "^17.0.2",
53
- "sinon": "^10.0.0",
54
- "sinon-chai": "^3.3.0",
51
+ "semantic-release": "^18.0.1",
52
+ "sinon": "^13.0.1",
53
+ "sinon-chai": "^3.7.0",
55
54
  "typescript": "^4.2.2"
56
55
  },
57
56
  "scripts": {
@@ -61,7 +60,7 @@
61
60
  "lint:js": "eslint --cache --cache-location './.cache/eslint' '**/*.js'",
62
61
  "lint:js:fix": "eslint --cache --cache-location './.cache/eslint' --fix '**/*.js'",
63
62
  "lint:ts": "dtslint types",
64
- "test": "nyc mocha tests",
63
+ "test": "nyc --reporter=lcov --reporter=text mocha tests",
65
64
  "test:coverage": "open coverage/lcov-report/index.html"
66
65
  },
67
66
  "license": "MIT",
package/types/index.d.ts CHANGED
@@ -240,7 +240,7 @@ declare namespace nock {
240
240
  options?: Options
241
241
  }
242
242
 
243
- type BackMode = 'wild' | 'dryrun' | 'record' | 'lockdown'
243
+ type BackMode = 'wild' | 'dryrun' | 'record' | 'update' | 'lockdown'
244
244
 
245
245
  interface Back {
246
246
  currentMode: BackMode
package/CHANGELOG.md DELETED
@@ -1,6 +0,0 @@
1
- # Changelog
2
-
3
- Nock’s changelog can be found directly in the [GitHub release notes](https://github.com/nock/nock/releases).
4
- These are automatically created by [semantic-release](https://github.com/semantic-release/semantic-release) based on their [commit message conventions](https://semantic-release.gitbook.io/semantic-release#commit-message-format).
5
-
6
- Migration guides are available for major versions in the [migration guides directory](https://github.com/nock/nock/tree/main/migration_guides).