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,32 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* @public
|
|
15
|
-
* @param {String|RegExp} matcher=RegExp.new('.*') Expression to match
|
|
16
|
-
* @example
|
|
17
|
-
* // Enables all real requests
|
|
18
|
-
* nock.enableNetConnect();
|
|
19
|
-
* @example
|
|
20
|
-
* // Enables real requests for url that matches google
|
|
21
|
-
* nock.enableNetConnect('google');
|
|
22
|
-
* @example
|
|
23
|
-
* // Enables real requests for url that matches google and amazon
|
|
24
|
-
* nock.enableNetConnect(/(google|amazon)/);
|
|
25
|
-
* @example
|
|
26
|
-
* // Enables real requests for url that includes google
|
|
27
|
-
* nock.enableNetConnect(host => host.includes('google'));
|
|
28
|
-
*/
|
|
29
|
-
function enableNetConnect(matcher) {
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import * as common from './common.js'
|
|
4
|
+
import { intercept as debug } from './debug.js'
|
|
5
|
+
import * as builtinMock from './interceptors/builtin.js'
|
|
6
|
+
|
|
7
|
+
let allInterceptors = {}
|
|
8
|
+
let allowNetConnect
|
|
9
|
+
let _isActive = false
|
|
10
|
+
|
|
11
|
+
function enableNetConnect(
|
|
12
|
+
matcher ,
|
|
13
|
+
) {
|
|
30
14
|
if (typeof matcher === 'string') {
|
|
31
15
|
allowNetConnect = new RegExp(matcher)
|
|
32
16
|
} else if (matcher instanceof RegExp) {
|
|
@@ -38,18 +22,12 @@ function enableNetConnect(matcher) {
|
|
|
38
22
|
}
|
|
39
23
|
}
|
|
40
24
|
|
|
41
|
-
function isEnabledForNetConnect(url) {
|
|
42
|
-
const enabled = allowNetConnect && allowNetConnect.test(url)
|
|
25
|
+
function isEnabledForNetConnect(url ) {
|
|
26
|
+
const enabled = !!(allowNetConnect && allowNetConnect.test(url))
|
|
43
27
|
debug('Net connect', enabled ? '' : 'not', 'enabled for', url)
|
|
44
28
|
return enabled
|
|
45
29
|
}
|
|
46
30
|
|
|
47
|
-
/**
|
|
48
|
-
* Disable all real requests.
|
|
49
|
-
* @public
|
|
50
|
-
* @example
|
|
51
|
-
* nock.disableNetConnect();
|
|
52
|
-
*/
|
|
53
31
|
function disableNetConnect() {
|
|
54
32
|
allowNetConnect = undefined
|
|
55
33
|
}
|
|
@@ -62,7 +40,13 @@ function isOff() {
|
|
|
62
40
|
return process.env.NOCK_OFF === 'true'
|
|
63
41
|
}
|
|
64
42
|
|
|
65
|
-
function addInterceptor(
|
|
43
|
+
function addInterceptor(
|
|
44
|
+
key ,
|
|
45
|
+
interceptor ,
|
|
46
|
+
scope ,
|
|
47
|
+
scopeOptions ,
|
|
48
|
+
host ,
|
|
49
|
+
) {
|
|
66
50
|
if (!(key in allInterceptors)) {
|
|
67
51
|
allInterceptors[key] = { key, interceptors: [] }
|
|
68
52
|
}
|
|
@@ -80,39 +64,35 @@ function addInterceptor(key, interceptor, scope, scopeOptions, host) {
|
|
|
80
64
|
allInterceptors[key].interceptors.push(interceptor)
|
|
81
65
|
}
|
|
82
66
|
|
|
83
|
-
function remove(interceptor) {
|
|
84
|
-
if (interceptor.__nock_scope
|
|
67
|
+
function remove(interceptor ) {
|
|
68
|
+
if (interceptor.__nock_scope?.shouldPersist() || --interceptor.counter > 0) {
|
|
85
69
|
return
|
|
86
70
|
}
|
|
87
71
|
|
|
88
|
-
const
|
|
72
|
+
const basePath = interceptor.basePath
|
|
89
73
|
const interceptors =
|
|
90
74
|
(allInterceptors[basePath] && allInterceptors[basePath].interceptors) || []
|
|
91
75
|
|
|
92
76
|
// TODO: There is a clearer way to write that we want to delete the first
|
|
93
77
|
// matching instance. I'm also not sure why we couldn't delete _all_
|
|
94
78
|
// matching instances.
|
|
95
|
-
interceptors.some(function (thisInterceptor, i) {
|
|
79
|
+
interceptors.some(function (thisInterceptor , i ) {
|
|
96
80
|
return thisInterceptor === interceptor ? interceptors.splice(i, 1) : false
|
|
97
81
|
})
|
|
98
82
|
}
|
|
99
83
|
|
|
100
84
|
function removeAll() {
|
|
101
85
|
Object.keys(allInterceptors).forEach(function (key) {
|
|
102
|
-
allInterceptors[key].interceptors.forEach(function (
|
|
86
|
+
allInterceptors[key].interceptors.forEach(function (
|
|
87
|
+
interceptor ,
|
|
88
|
+
) {
|
|
103
89
|
interceptor.scope.keyedInterceptors = {}
|
|
104
90
|
})
|
|
105
91
|
})
|
|
106
92
|
allInterceptors = {}
|
|
107
93
|
}
|
|
108
94
|
|
|
109
|
-
|
|
110
|
-
* Return all the Interceptors whose Scopes match against the base path of the provided options.
|
|
111
|
-
*
|
|
112
|
-
* @param {URL} url
|
|
113
|
-
* @returns {Interceptor[]}
|
|
114
|
-
*/
|
|
115
|
-
function interceptorsFor(url) {
|
|
95
|
+
function interceptorsFor(url ) {
|
|
116
96
|
debug('interceptors for %j', url.host)
|
|
117
97
|
|
|
118
98
|
const port = url.port || (url.protocol === 'https:' ? 443 : 80)
|
|
@@ -135,7 +115,7 @@ function interceptorsFor(url) {
|
|
|
135
115
|
|
|
136
116
|
// Keep the filtered scope (its key) to signal the rest of the module
|
|
137
117
|
// that this wasn't an exact but filtered match.
|
|
138
|
-
interceptors.forEach(ic => {
|
|
118
|
+
interceptors.forEach((ic ) => {
|
|
139
119
|
ic.__nock_filteredScope = ic.__nock_scopeKey
|
|
140
120
|
})
|
|
141
121
|
return interceptors
|
|
@@ -167,21 +147,30 @@ function interceptorsFor(url) {
|
|
|
167
147
|
return undefined
|
|
168
148
|
}
|
|
169
149
|
|
|
170
|
-
|
|
171
|
-
// Lazily import to avoid circular imports.
|
|
172
|
-
const Interceptor = require('./interceptor')
|
|
150
|
+
import { Interceptor as InterceptorClass } from './interceptor.js'
|
|
173
151
|
|
|
152
|
+
function removeInterceptor(
|
|
153
|
+
options
|
|
154
|
+
|
|
155
|
+
,
|
|
156
|
+
) {
|
|
174
157
|
let baseUrl, key, method, proto
|
|
175
|
-
if (options instanceof
|
|
176
|
-
baseUrl = options.basePath
|
|
177
|
-
key = options._key
|
|
158
|
+
if (options instanceof InterceptorClass) {
|
|
159
|
+
baseUrl = (options ).basePath
|
|
160
|
+
key = (options )._key
|
|
178
161
|
} else {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
162
|
+
const opts = options
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
proto = opts.proto ? opts.proto : 'http'
|
|
169
|
+
|
|
170
|
+
common.normalizeRequestOptions(opts)
|
|
171
|
+
baseUrl = `${proto}://${opts.host}`
|
|
172
|
+
method = (opts.method && opts.method.toUpperCase()) || 'GET'
|
|
173
|
+
key = `${method} ${baseUrl}${opts.path || '/'}`
|
|
185
174
|
}
|
|
186
175
|
|
|
187
176
|
if (
|
|
@@ -191,12 +180,16 @@ function removeInterceptor(options) {
|
|
|
191
180
|
for (let i = 0; i < allInterceptors[baseUrl].interceptors.length; i++) {
|
|
192
181
|
const interceptor = allInterceptors[baseUrl].interceptors[i]
|
|
193
182
|
if (
|
|
194
|
-
options instanceof
|
|
183
|
+
options instanceof InterceptorClass
|
|
195
184
|
? interceptor === options
|
|
196
185
|
: interceptor._key === key
|
|
197
186
|
) {
|
|
198
187
|
allInterceptors[baseUrl].interceptors.splice(i, 1)
|
|
199
188
|
interceptor.scope.remove(key, interceptor)
|
|
189
|
+
interceptor.scope.interceptors.splice(
|
|
190
|
+
interceptor.scope.interceptors.indexOf(interceptor),
|
|
191
|
+
1,
|
|
192
|
+
)
|
|
200
193
|
break
|
|
201
194
|
}
|
|
202
195
|
}
|
|
@@ -209,10 +202,14 @@ function removeInterceptor(options) {
|
|
|
209
202
|
|
|
210
203
|
function interceptorScopes() {
|
|
211
204
|
const nestedInterceptors = Object.values(allInterceptors).map(
|
|
212
|
-
i => i.interceptors,
|
|
205
|
+
(i ) => i.interceptors,
|
|
206
|
+
)
|
|
207
|
+
const scopes = new Set(
|
|
208
|
+
([] )
|
|
209
|
+
.concat(...nestedInterceptors)
|
|
210
|
+
.map((i ) => i.scope),
|
|
213
211
|
)
|
|
214
|
-
|
|
215
|
-
return [...scopes]
|
|
212
|
+
return [...scopes]
|
|
216
213
|
}
|
|
217
214
|
|
|
218
215
|
function isDone() {
|
|
@@ -220,61 +217,51 @@ function isDone() {
|
|
|
220
217
|
}
|
|
221
218
|
|
|
222
219
|
function pendingMocks() {
|
|
223
|
-
return [].concat(
|
|
220
|
+
return ([] ).concat(
|
|
221
|
+
...interceptorScopes().map(scope => scope.pendingMocks()),
|
|
222
|
+
)
|
|
224
223
|
}
|
|
225
224
|
|
|
226
225
|
function activeMocks() {
|
|
227
|
-
return [].concat(
|
|
226
|
+
return ([] ).concat(
|
|
227
|
+
...interceptorScopes().map(scope => scope.activeMocks()),
|
|
228
|
+
)
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
function activate() {
|
|
231
|
-
if (!
|
|
232
|
+
if (!_isActive) {
|
|
232
233
|
builtinMock.activate()
|
|
233
|
-
|
|
234
|
-
// Lazy load undiciMock only when activate is called
|
|
235
|
-
if (!undiciMock) {
|
|
236
|
-
try {
|
|
237
|
-
undiciMock = require('./interceptors/undici')
|
|
238
|
-
} catch (err) {
|
|
239
|
-
if (err.code !== 'MODULE_NOT_FOUND') {
|
|
240
|
-
throw err
|
|
241
|
-
}
|
|
242
|
-
debug(
|
|
243
|
-
'Undici mocking is disabled because the undici module is not installed',
|
|
244
|
-
)
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
undiciMock?.activate()
|
|
249
|
-
isActive = true
|
|
234
|
+
_isActive = true
|
|
250
235
|
} else {
|
|
251
236
|
throw new Error('Nock already active')
|
|
252
237
|
}
|
|
253
238
|
}
|
|
254
239
|
|
|
255
240
|
function deactivate() {
|
|
256
|
-
if (
|
|
241
|
+
if (_isActive) {
|
|
257
242
|
builtinMock.deactivate()
|
|
258
|
-
|
|
259
|
-
isActive = false
|
|
243
|
+
_isActive = false
|
|
260
244
|
}
|
|
261
245
|
}
|
|
262
246
|
|
|
263
|
-
|
|
247
|
+
const isActiveFn = () => _isActive
|
|
248
|
+
const abortPendingRequests = common.removeAllTimers
|
|
249
|
+
|
|
250
|
+
export {
|
|
264
251
|
addInterceptor,
|
|
265
252
|
remove,
|
|
266
253
|
removeAll,
|
|
267
254
|
removeInterceptor,
|
|
268
255
|
isOn,
|
|
269
256
|
activate,
|
|
270
|
-
|
|
257
|
+
isActiveFn as isActive,
|
|
271
258
|
isDone,
|
|
272
259
|
pendingMocks,
|
|
273
260
|
activeMocks,
|
|
274
261
|
enableNetConnect,
|
|
275
262
|
disableNetConnect,
|
|
276
|
-
restoreOverriddenClientRequest
|
|
277
|
-
abortPendingRequests
|
|
263
|
+
deactivate as restoreOverriddenClientRequest,
|
|
264
|
+
abortPendingRequests,
|
|
278
265
|
interceptorsFor,
|
|
279
266
|
isEnabledForNetConnect,
|
|
280
267
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ReadStream } from 'node:fs';
|
|
2
|
+
import type { Scope, Options } from './scope.ts';
|
|
3
|
+
export type DataMatcher = boolean | number | string | null | undefined | RegExp | DataMatcherArray | DataMatcherMap;
|
|
4
|
+
export type DataMatcherArray = ReadonlyArray<DataMatcher>;
|
|
5
|
+
export type DataMatcherMap = {
|
|
6
|
+
[key: string]: DataMatcher;
|
|
7
|
+
};
|
|
8
|
+
export type RequestBodyMatcher = string | Buffer | RegExp | DataMatcherArray | DataMatcherMap | ((body: any) => boolean);
|
|
9
|
+
export type RequestHeaderMatcher = string | RegExp | ((fieldValue: string | null) => boolean);
|
|
10
|
+
export type Body = string | Record<string, any>;
|
|
11
|
+
export type ReplyBody = Body | Buffer | ReadStream;
|
|
12
|
+
export type ReplyHeaderFunction = (req: Request, body?: string | Buffer) => string | string[] | Promise<string | string[]>;
|
|
13
|
+
export type ReplyHeaderValue = string | string[] | ReplyHeaderFunction;
|
|
14
|
+
export type ReplyHeaders = Record<string, ReplyHeaderValue> | Map<string, ReplyHeaderValue> | ReplyHeaderValue[];
|
|
15
|
+
export type StatusCode = number;
|
|
16
|
+
export type ReplyFnResult = readonly [StatusCode] | readonly [StatusCode, ReplyBody] | readonly [StatusCode, ReplyBody, ReplyHeaders];
|
|
17
|
+
import { URLSearchParams } from 'node:url';
|
|
18
|
+
declare class Interceptor {
|
|
19
|
+
constructor(scope: Scope, uri: string | RegExp | ((path: string) => boolean), method: string, requestBody?: RequestBodyMatcher, interceptorOptions?: Options);
|
|
20
|
+
optionally(flag?: boolean): this;
|
|
21
|
+
passthrough(): Scope;
|
|
22
|
+
replyWithError(errorMessage: string | Error | Record<string, any>): Scope;
|
|
23
|
+
reply(statusCode: any, body?: any, rawHeaders?: ReplyHeaders): Scope;
|
|
24
|
+
replyWithFile(statusCode: number, filePath: string, headers?: ReplyHeaders): Scope;
|
|
25
|
+
reqheaderMatches(expected: RequestHeaderMatcher, actual: string | null, key: string): boolean;
|
|
26
|
+
match(request: Request, body: string): string[];
|
|
27
|
+
matchOrigin(request: Request): boolean;
|
|
28
|
+
matchHostName(hostname: string): boolean;
|
|
29
|
+
matchQuery(options: Record<string, any>): any;
|
|
30
|
+
filteringPath(...args: any[]): this;
|
|
31
|
+
markConsumed(): void;
|
|
32
|
+
matchHeader(name: string, value: RequestHeaderMatcher): this;
|
|
33
|
+
basicAuth({ user, pass }: {
|
|
34
|
+
user: string;
|
|
35
|
+
pass?: string;
|
|
36
|
+
}): this;
|
|
37
|
+
query(queries: boolean | string | URLSearchParams | Record<string, any> | ((queryObject: Record<string, any>) => boolean)): this;
|
|
38
|
+
times(newCounter: number): this;
|
|
39
|
+
once(): this;
|
|
40
|
+
twice(): this;
|
|
41
|
+
thrice(): this;
|
|
42
|
+
delay(ms: number): this;
|
|
43
|
+
}
|
|
44
|
+
export { Interceptor };
|