nock 15.0.0 → 15.0.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/README.md +39 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +109 -0
- package/dist/lib/back.d.ts +44 -0
- package/{lib → dist/lib}/back.js +111 -84
- package/dist/lib/common.d.ts +27 -0
- package/{lib → dist/lib}/common.js +80 -190
- package/dist/lib/debug.d.ts +9 -0
- package/dist/lib/debug.js +17 -0
- package/dist/lib/global_emitter.d.ts +11 -0
- package/dist/lib/global_emitter.js +13 -0
- package/dist/lib/handle-request.d.ts +2 -0
- package/{lib → dist/lib}/handle-request.js +24 -39
- package/dist/lib/intercept.d.ts +25 -0
- package/{lib → dist/lib}/intercept.js +81 -94
- package/dist/lib/interceptor.d.ts +44 -0
- package/{lib → dist/lib}/interceptor.js +223 -119
- package/dist/lib/interceptors/builtin.d.ts +3 -0
- package/dist/lib/interceptors/builtin.js +56 -0
- package/dist/lib/match_body.d.ts +1 -0
- package/{lib → dist/lib}/match_body.js +20 -27
- package/dist/lib/playback_interceptor.d.ts +8 -0
- package/{lib → dist/lib}/playback_interceptor.js +52 -62
- package/dist/lib/recorder.d.ts +13 -0
- package/{lib → dist/lib}/recorder.js +63 -92
- package/dist/lib/scope.d.ts +59 -0
- package/{lib → dist/lib}/scope.js +158 -87
- package/dist/lib/stringify.d.ts +24 -0
- package/dist/lib/stringify.js +50 -0
- package/dist/lib/utils/node/index.d.ts +4 -0
- package/dist/lib/utils/node/index.js +16 -0
- package/package.json +25 -22
- package/index.js +0 -55
- package/lib/create_response.js +0 -53
- package/lib/debug.js +0 -12
- package/lib/global_emitter.js +0 -5
- package/lib/interceptors/builtin.js +0 -67
- package/lib/interceptors/undici.js +0 -78
- package/lib/utils/node/index.js +0 -33
- package/types/index.d.ts +0 -319
|
@@ -1,26 +1,132 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
import fs from 'node:fs'
|
|
49
|
+
import querystring from 'node:querystring'
|
|
50
|
+
import { URL, URLSearchParams } from 'node:url'
|
|
51
|
+
|
|
52
|
+
import stringify from './stringify.js'
|
|
53
|
+
import * as common from './common.js'
|
|
54
|
+
import { remove } from './intercept.js'
|
|
55
|
+
import matchBody from './match_body.js'
|
|
56
|
+
|
|
57
|
+
class Interceptor {
|
|
58
|
+
/** @internal */
|
|
59
|
+
|
|
60
|
+
/** @internal */
|
|
61
|
+
|
|
62
|
+
/** @internal */
|
|
63
|
+
|
|
64
|
+
/** @internal */
|
|
65
|
+
|
|
66
|
+
/** @internal */
|
|
67
|
+
|
|
68
|
+
/** @internal */
|
|
69
|
+
|
|
70
|
+
/** @internal */
|
|
71
|
+
|
|
72
|
+
/** @internal */
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/** @internal */
|
|
79
|
+
|
|
80
|
+
/** @internal */
|
|
81
|
+
|
|
82
|
+
/** @internal */
|
|
83
|
+
|
|
84
|
+
/** @internal */
|
|
85
|
+
|
|
86
|
+
/** @internal */
|
|
87
|
+
|
|
88
|
+
/** @internal */
|
|
89
|
+
|
|
90
|
+
/** @internal */
|
|
91
|
+
|
|
92
|
+
/** @internal */
|
|
93
|
+
|
|
94
|
+
/** @internal */
|
|
95
|
+
|
|
96
|
+
/** @internal */
|
|
97
|
+
|
|
98
|
+
/** @internal */
|
|
99
|
+
|
|
100
|
+
/** @internal */
|
|
101
|
+
|
|
102
|
+
/** @internal */
|
|
103
|
+
|
|
104
|
+
/** @internal */
|
|
105
|
+
|
|
106
|
+
/** @internal */
|
|
107
|
+
|
|
108
|
+
/** @internal */
|
|
109
|
+
|
|
110
|
+
/** @internal */
|
|
111
|
+
|
|
112
|
+
/** @internal */
|
|
113
|
+
|
|
114
|
+
/** @internal */
|
|
115
|
+
|
|
116
|
+
/** @internal */
|
|
117
|
+
|
|
118
|
+
/** @internal */
|
|
119
|
+
|
|
120
|
+
/** @internal */
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
constructor(
|
|
124
|
+
scope ,
|
|
125
|
+
uri ,
|
|
126
|
+
method ,
|
|
127
|
+
requestBody ,
|
|
128
|
+
interceptorOptions ,
|
|
129
|
+
) {
|
|
24
130
|
const uriIsStr = typeof uri === 'string'
|
|
25
131
|
// Check for leading slash. Uri can be either a string or a regexp, but
|
|
26
132
|
// When enabled filteringScope ignores the passed URL entirely so we skip validation.
|
|
@@ -29,8 +135,8 @@ module.exports = class Interceptor {
|
|
|
29
135
|
uriIsStr &&
|
|
30
136
|
!scope.scopeOptions.filteringScope &&
|
|
31
137
|
!scope.basePathname &&
|
|
32
|
-
!uri.startsWith('/') &&
|
|
33
|
-
!uri.startsWith('*')
|
|
138
|
+
!(uri ).startsWith('/') &&
|
|
139
|
+
!(uri ).startsWith('*')
|
|
34
140
|
) {
|
|
35
141
|
throw Error(
|
|
36
142
|
`Non-wildcard URL path strings must begin with a slash (otherwise they won't match anything) (got: ${uri})`,
|
|
@@ -70,9 +176,20 @@ module.exports = class Interceptor {
|
|
|
70
176
|
this.delayBodyInMs = 0
|
|
71
177
|
|
|
72
178
|
this.optional = false
|
|
179
|
+
this.isPassthrough = false
|
|
180
|
+
|
|
181
|
+
this.__nock_filteredScope = undefined
|
|
182
|
+
this.__nock_scopeKey = undefined
|
|
183
|
+
this.__nock_scope = undefined
|
|
184
|
+
this.__nock_scopeOptions = undefined
|
|
185
|
+
this.__nock_scopeHost = undefined
|
|
186
|
+
this.interceptionCounter = 0
|
|
187
|
+
this.statusCode = undefined
|
|
188
|
+
this.headers = undefined
|
|
189
|
+
this.rawHeaders = []
|
|
73
190
|
|
|
74
191
|
// strip off literal query parameters if they were provided as part of the URI
|
|
75
|
-
if (uriIsStr && uri.includes('?')) {
|
|
192
|
+
if (uriIsStr && (uri ).includes('?')) {
|
|
76
193
|
// localhost is a dummy value because the URL constructor errors for only relative inputs
|
|
77
194
|
const parsedURL = new URL(this.path, 'http://localhost')
|
|
78
195
|
this.path = parsedURL.pathname
|
|
@@ -92,7 +209,19 @@ module.exports = class Interceptor {
|
|
|
92
209
|
return this
|
|
93
210
|
}
|
|
94
211
|
|
|
95
|
-
|
|
212
|
+
passthrough() {
|
|
213
|
+
this.isPassthrough = true
|
|
214
|
+
|
|
215
|
+
this.options = {
|
|
216
|
+
...this.scope.scopeOptions,
|
|
217
|
+
...this.options,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.scope.add(this._key, this)
|
|
221
|
+
return this.scope
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
replyWithError(errorMessage ) {
|
|
96
225
|
this.errorMessage = errorMessage
|
|
97
226
|
|
|
98
227
|
this.options = {
|
|
@@ -104,7 +233,7 @@ module.exports = class Interceptor {
|
|
|
104
233
|
return this.scope
|
|
105
234
|
}
|
|
106
235
|
|
|
107
|
-
reply(statusCode, body, rawHeaders) {
|
|
236
|
+
reply(statusCode , body , rawHeaders ) {
|
|
108
237
|
// support the format of only passing in a callback
|
|
109
238
|
if (typeof statusCode === 'function') {
|
|
110
239
|
if (arguments.length > 1) {
|
|
@@ -163,10 +292,20 @@ module.exports = class Interceptor {
|
|
|
163
292
|
throw new Error('Error encoding response body into JSON')
|
|
164
293
|
}
|
|
165
294
|
|
|
166
|
-
if (!this.headers['content-type']) {
|
|
295
|
+
if (!this.headers ['content-type']) {
|
|
167
296
|
// https://tools.ietf.org/html/rfc7231#section-3.1.1.5
|
|
168
297
|
this.rawHeaders.push('Content-Type', 'application/json')
|
|
169
298
|
}
|
|
299
|
+
|
|
300
|
+
// Fix content-length header if it exists and doesn't match the stringified body
|
|
301
|
+
const contentLengthIndex = this.rawHeaders.findIndex(
|
|
302
|
+
(value , index ) =>
|
|
303
|
+
index % 2 === 0 && value.toLowerCase() === 'content-length',
|
|
304
|
+
)
|
|
305
|
+
if (contentLengthIndex !== -1) {
|
|
306
|
+
const actualLength = Buffer.byteLength(body, 'utf8')
|
|
307
|
+
this.rawHeaders[contentLengthIndex + 1] = String(actualLength)
|
|
308
|
+
}
|
|
170
309
|
}
|
|
171
310
|
|
|
172
311
|
if (this.scope.contentLen) {
|
|
@@ -187,7 +326,7 @@ module.exports = class Interceptor {
|
|
|
187
326
|
return this.scope
|
|
188
327
|
}
|
|
189
328
|
|
|
190
|
-
replyWithFile(statusCode, filePath, headers) {
|
|
329
|
+
replyWithFile(statusCode , filePath , headers ) {
|
|
191
330
|
if (!fs) {
|
|
192
331
|
throw new Error('No fs')
|
|
193
332
|
}
|
|
@@ -203,7 +342,11 @@ module.exports = class Interceptor {
|
|
|
203
342
|
)
|
|
204
343
|
}
|
|
205
344
|
|
|
206
|
-
reqheaderMatches(
|
|
345
|
+
reqheaderMatches(
|
|
346
|
+
expected ,
|
|
347
|
+
actual ,
|
|
348
|
+
key ,
|
|
349
|
+
) {
|
|
207
350
|
if (expected !== undefined && actual !== undefined) {
|
|
208
351
|
if (typeof expected === 'function') {
|
|
209
352
|
return expected(actual)
|
|
@@ -221,17 +364,12 @@ module.exports = class Interceptor {
|
|
|
221
364
|
return false
|
|
222
365
|
}
|
|
223
366
|
|
|
224
|
-
|
|
225
|
-
* @param {Request} request
|
|
226
|
-
* @param {string} body - string or hex
|
|
227
|
-
* @returns {string[]}
|
|
228
|
-
*/
|
|
229
|
-
match(request, body) {
|
|
367
|
+
match(request , body ) {
|
|
230
368
|
const url = new URL(request.url)
|
|
231
369
|
// TODO: fix request log to string
|
|
232
370
|
this.scope.logger('attempting match %j, body = %j', request, body)
|
|
233
371
|
|
|
234
|
-
const mismatches
|
|
372
|
+
const mismatches = []
|
|
235
373
|
let path = url.pathname + url.search
|
|
236
374
|
let matchKey
|
|
237
375
|
|
|
@@ -245,7 +383,13 @@ module.exports = class Interceptor {
|
|
|
245
383
|
path = this.scope.transformPathFunction(path)
|
|
246
384
|
}
|
|
247
385
|
|
|
248
|
-
const requestMatchesFilter = ({
|
|
386
|
+
const requestMatchesFilter = ({
|
|
387
|
+
name,
|
|
388
|
+
value: predicate,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
) => {
|
|
249
393
|
const headerValue = request.headers.get(name)
|
|
250
394
|
if (typeof predicate === 'function') {
|
|
251
395
|
return predicate(headerValue)
|
|
@@ -265,7 +409,7 @@ module.exports = class Interceptor {
|
|
|
265
409
|
}
|
|
266
410
|
}
|
|
267
411
|
|
|
268
|
-
const reqHeadersMatch = Object.keys(this.reqheaders).every(key =>
|
|
412
|
+
const reqHeadersMatch = Object.keys(this.reqheaders).every((key ) =>
|
|
269
413
|
this.reqheaderMatches(
|
|
270
414
|
this.reqheaders[key],
|
|
271
415
|
request.headers.get(key),
|
|
@@ -288,7 +432,7 @@ module.exports = class Interceptor {
|
|
|
288
432
|
mismatches.push(msg)
|
|
289
433
|
}
|
|
290
434
|
|
|
291
|
-
const badHeaders = this.badheaders.filter(header =>
|
|
435
|
+
const badHeaders = this.badheaders.filter((header ) =>
|
|
292
436
|
request.headers.has(header),
|
|
293
437
|
)
|
|
294
438
|
|
|
@@ -303,7 +447,7 @@ module.exports = class Interceptor {
|
|
|
303
447
|
this.scope.logger('query matching skipped')
|
|
304
448
|
} else {
|
|
305
449
|
// can't rely on pathname or search being in the options, but path has a default
|
|
306
|
-
const [pathname, search] = path.split('?')
|
|
450
|
+
const [pathname, search] = (path ).split('?')
|
|
307
451
|
const matchQueries = this.matchQuery({ search })
|
|
308
452
|
|
|
309
453
|
if (!matchQueries) {
|
|
@@ -322,12 +466,14 @@ module.exports = class Interceptor {
|
|
|
322
466
|
// necessarily match and we have to remove the scope that was matched (vs.
|
|
323
467
|
// that was defined).
|
|
324
468
|
if (this.__nock_filteredScope) {
|
|
325
|
-
matchKey = this.__nock_filteredScope
|
|
469
|
+
matchKey = this.__nock_filteredScope
|
|
326
470
|
} else {
|
|
327
471
|
matchKey = common.normalizeOrigin(url)
|
|
328
472
|
}
|
|
329
473
|
|
|
330
|
-
if (
|
|
474
|
+
if (
|
|
475
|
+
!common.matchStringOrRegexp(matchKey, this.basePath )
|
|
476
|
+
) {
|
|
331
477
|
const msg = `Base path mismatch: expected ${this.basePath}, got ${matchKey}`
|
|
332
478
|
this.scope.logger(msg)
|
|
333
479
|
mismatches.push(msg)
|
|
@@ -339,7 +485,9 @@ module.exports = class Interceptor {
|
|
|
339
485
|
this.scope.logger(msg)
|
|
340
486
|
mismatches.push(msg)
|
|
341
487
|
}
|
|
342
|
-
} else if (
|
|
488
|
+
} else if (
|
|
489
|
+
!common.matchStringOrRegexp(path, this.path )
|
|
490
|
+
) {
|
|
343
491
|
const msg = `Path mismatch: expected ${this.path}, got ${path}`
|
|
344
492
|
this.scope.logger(msg)
|
|
345
493
|
mismatches.push(msg)
|
|
@@ -360,13 +508,7 @@ module.exports = class Interceptor {
|
|
|
360
508
|
return mismatches
|
|
361
509
|
}
|
|
362
510
|
|
|
363
|
-
|
|
364
|
-
* Return true when the interceptor's method, protocol, host, port, and path
|
|
365
|
-
* match the provided options.
|
|
366
|
-
*
|
|
367
|
-
* @param {Request} request
|
|
368
|
-
*/
|
|
369
|
-
matchOrigin(request) {
|
|
511
|
+
matchOrigin(request ) {
|
|
370
512
|
const url = new URL(request.url)
|
|
371
513
|
const isPathFn = typeof this.path === 'function'
|
|
372
514
|
const isRegex = this.path instanceof RegExp
|
|
@@ -384,28 +526,29 @@ module.exports = class Interceptor {
|
|
|
384
526
|
if (this.scope.transformPathFunction) {
|
|
385
527
|
path = this.scope.transformPathFunction(path)
|
|
386
528
|
}
|
|
387
|
-
const comparisonKey =
|
|
529
|
+
const comparisonKey =
|
|
530
|
+
isPathFn || isRegex ? (this.__nock_scopeKey ) : this._key
|
|
388
531
|
const matchKey = `${method} ${url.protocol}//${url.hostname}:${port}${path}`
|
|
389
532
|
|
|
390
533
|
if (isPathFn) {
|
|
391
|
-
return !!(matchKey.match(comparisonKey) && this.path(path))
|
|
534
|
+
return !!(matchKey.match(comparisonKey) && (this.path )(path))
|
|
392
535
|
}
|
|
393
536
|
|
|
394
537
|
if (isRegex && !isRegexBasePath) {
|
|
395
|
-
return !!matchKey.match(comparisonKey) && this.path.test(path)
|
|
538
|
+
return !!matchKey.match(comparisonKey) && (this.path ).test(path)
|
|
396
539
|
}
|
|
397
540
|
|
|
398
541
|
if (isRegexBasePath) {
|
|
399
|
-
return
|
|
542
|
+
return (
|
|
543
|
+
(this.scope.basePath ).test(matchKey) &&
|
|
544
|
+
!!path.match(this.path )
|
|
545
|
+
)
|
|
400
546
|
}
|
|
401
547
|
|
|
402
548
|
return comparisonKey === matchKey
|
|
403
549
|
}
|
|
404
550
|
|
|
405
|
-
|
|
406
|
-
* @param {string} hostname
|
|
407
|
-
*/
|
|
408
|
-
matchHostName(hostname) {
|
|
551
|
+
matchHostName(hostname ) {
|
|
409
552
|
const { basePath } = this.scope
|
|
410
553
|
|
|
411
554
|
if (basePath instanceof RegExp) {
|
|
@@ -415,7 +558,7 @@ module.exports = class Interceptor {
|
|
|
415
558
|
return hostname === this.scope.urlParts.hostname
|
|
416
559
|
}
|
|
417
560
|
|
|
418
|
-
matchQuery(options) {
|
|
561
|
+
matchQuery(options ) {
|
|
419
562
|
if (this.queries === true) {
|
|
420
563
|
return true
|
|
421
564
|
}
|
|
@@ -431,8 +574,8 @@ module.exports = class Interceptor {
|
|
|
431
574
|
return common.dataEqual(this.queries, reqQueries)
|
|
432
575
|
}
|
|
433
576
|
|
|
434
|
-
filteringPath(...args) {
|
|
435
|
-
this.scope.filteringPath(
|
|
577
|
+
filteringPath(...args ) {
|
|
578
|
+
;(this.scope.filteringPath ).apply(this.scope, args)
|
|
436
579
|
return this
|
|
437
580
|
}
|
|
438
581
|
|
|
@@ -440,7 +583,7 @@ module.exports = class Interceptor {
|
|
|
440
583
|
// by request body?
|
|
441
584
|
|
|
442
585
|
markConsumed() {
|
|
443
|
-
this.interceptionCounter
|
|
586
|
+
this.interceptionCounter = (this.interceptionCounter || 0) + 1
|
|
444
587
|
|
|
445
588
|
remove(this)
|
|
446
589
|
|
|
@@ -449,27 +592,25 @@ module.exports = class Interceptor {
|
|
|
449
592
|
}
|
|
450
593
|
}
|
|
451
594
|
|
|
452
|
-
matchHeader(name, value) {
|
|
595
|
+
matchHeader(name , value ) {
|
|
453
596
|
this.interceptorMatchHeaders.push({ name, value })
|
|
454
597
|
return this
|
|
455
598
|
}
|
|
456
599
|
|
|
457
|
-
basicAuth({ user, pass = '' }) {
|
|
600
|
+
basicAuth({ user, pass = '' } ) {
|
|
458
601
|
const encoded = Buffer.from(`${user}:${pass}`).toString('base64')
|
|
459
602
|
this.matchHeader('authorization', `Basic ${encoded}`)
|
|
460
603
|
return this
|
|
461
604
|
}
|
|
462
605
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
*/
|
|
472
|
-
query(queries) {
|
|
606
|
+
query(
|
|
607
|
+
queries
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
,
|
|
613
|
+
) {
|
|
473
614
|
if (this.queries !== null) {
|
|
474
615
|
throw Error(`Query parameters have already been defined`)
|
|
475
616
|
}
|
|
@@ -498,26 +639,17 @@ module.exports = class Interceptor {
|
|
|
498
639
|
throw Error(`Argument Error: ${queries}`)
|
|
499
640
|
}
|
|
500
641
|
|
|
501
|
-
this.queries = {}
|
|
642
|
+
this.queries = {}
|
|
502
643
|
for (const [key, value] of Object.entries(queries)) {
|
|
503
644
|
const formatted = common.formatQueryValue(key, value, strFormattingFn)
|
|
504
645
|
const [formattedKey, formattedValue] = formatted
|
|
505
|
-
this.queries[formattedKey] = formattedValue
|
|
646
|
+
;(this.queries )[formattedKey] = formattedValue
|
|
506
647
|
}
|
|
507
648
|
|
|
508
649
|
return this
|
|
509
650
|
}
|
|
510
651
|
|
|
511
|
-
|
|
512
|
-
* Set number of times will repeat the interceptor
|
|
513
|
-
* @name times
|
|
514
|
-
* @param newCounter Number of times to repeat (should be > 0)
|
|
515
|
-
* @public
|
|
516
|
-
* @example
|
|
517
|
-
* // Will repeat mock 5 times for same king of request
|
|
518
|
-
* nock('http://zombo.com).get('/').times(5).reply(200, 'Ok');
|
|
519
|
-
*/
|
|
520
|
-
times(newCounter) {
|
|
652
|
+
times(newCounter ) {
|
|
521
653
|
if (newCounter < 1) {
|
|
522
654
|
return this
|
|
523
655
|
}
|
|
@@ -527,49 +659,19 @@ module.exports = class Interceptor {
|
|
|
527
659
|
return this
|
|
528
660
|
}
|
|
529
661
|
|
|
530
|
-
/**
|
|
531
|
-
* An sugar syntax for times(1)
|
|
532
|
-
* @name once
|
|
533
|
-
* @see {@link times}
|
|
534
|
-
* @public
|
|
535
|
-
* @example
|
|
536
|
-
* nock('http://zombo.com).get('/').once().reply(200, 'Ok');
|
|
537
|
-
*/
|
|
538
662
|
once() {
|
|
539
663
|
return this.times(1)
|
|
540
664
|
}
|
|
541
665
|
|
|
542
|
-
/**
|
|
543
|
-
* An sugar syntax for times(2)
|
|
544
|
-
* @name twice
|
|
545
|
-
* @see {@link times}
|
|
546
|
-
* @public
|
|
547
|
-
* @example
|
|
548
|
-
* nock('http://zombo.com).get('/').twice().reply(200, 'Ok');
|
|
549
|
-
*/
|
|
550
666
|
twice() {
|
|
551
667
|
return this.times(2)
|
|
552
668
|
}
|
|
553
669
|
|
|
554
|
-
/**
|
|
555
|
-
* An sugar syntax for times(3).
|
|
556
|
-
* @name thrice
|
|
557
|
-
* @see {@link times}
|
|
558
|
-
* @public
|
|
559
|
-
* @example
|
|
560
|
-
* nock('http://zombo.com).get('/').thrice().reply(200, 'Ok');
|
|
561
|
-
*/
|
|
562
670
|
thrice() {
|
|
563
671
|
return this.times(3)
|
|
564
672
|
}
|
|
565
673
|
|
|
566
|
-
|
|
567
|
-
* Delay the response by a certain number of ms.
|
|
568
|
-
*
|
|
569
|
-
* @param {number} ms - Number of milliseconds to wait before response is sent
|
|
570
|
-
* @return {Interceptor} - the current interceptor for chaining
|
|
571
|
-
*/
|
|
572
|
-
delay(ms) {
|
|
674
|
+
delay(ms ) {
|
|
573
675
|
if (typeof ms === 'number') {
|
|
574
676
|
this.delayBodyInMs = ms
|
|
575
677
|
return this
|
|
@@ -578,3 +680,5 @@ module.exports = class Interceptor {
|
|
|
578
680
|
}
|
|
579
681
|
}
|
|
580
682
|
}
|
|
683
|
+
|
|
684
|
+
export { Interceptor }
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as common from '../common.js'
|
|
2
|
+
import handleRequest from '../handle-request.js'
|
|
3
|
+
import { setGetRequestBody } from '../utils/node/index.js'
|
|
4
|
+
import { BatchInterceptor } from '@mswjs/interceptors'
|
|
5
|
+
import { FetchInterceptor } from '@mswjs/interceptors/fetch'
|
|
6
|
+
import { HttpRequestInterceptor } from '@mswjs/interceptors/http'
|
|
7
|
+
|
|
8
|
+
const interceptor = new BatchInterceptor({
|
|
9
|
+
name: 'intercept',
|
|
10
|
+
interceptors: [new HttpRequestInterceptor(), new FetchInterceptor()],
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
function activate() {
|
|
14
|
+
interceptor.apply()
|
|
15
|
+
|
|
16
|
+
// Force msw to forward Nock's error instead of coerce it into 500 error
|
|
17
|
+
interceptor.on('unhandledException', ({ controller, error } ) => {
|
|
18
|
+
controller.errorWith(error)
|
|
19
|
+
})
|
|
20
|
+
interceptor.on(
|
|
21
|
+
'request',
|
|
22
|
+
async function ({ request, controller, initiator }) {
|
|
23
|
+
if (request.headers.get('expect') === '100-continue') {
|
|
24
|
+
// We currently do not support mocking 100-continue responses, so they are passed through for now.
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If this is GET request with body, we need to read the body from the socket because Fetch API doesn't support this.
|
|
29
|
+
const requestBodyBuffer = common.decompressRequestBody(
|
|
30
|
+
await request.clone().arrayBuffer(),
|
|
31
|
+
request.headers.get('content-encoding') || '',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const decompressedRequest = new Request(request, {
|
|
35
|
+
body:
|
|
36
|
+
requestBodyBuffer.byteLength > 0 && request.method !== 'GET'
|
|
37
|
+
? requestBodyBuffer
|
|
38
|
+
: undefined,
|
|
39
|
+
})
|
|
40
|
+
if (requestBodyBuffer.byteLength > 0 && request.method === 'GET') {
|
|
41
|
+
setGetRequestBody(decompressedRequest, requestBodyBuffer)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const response = await handleRequest(decompressedRequest)
|
|
45
|
+
if (response) {
|
|
46
|
+
controller.respondWith(response)
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function deactivate() {
|
|
53
|
+
interceptor.dispose()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { activate, deactivate }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function matchBody(request: Request, spec: any, body: string): any;
|