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.
Files changed (40) hide show
  1. package/README.md +39 -0
  2. package/dist/index.d.ts +60 -0
  3. package/dist/index.js +109 -0
  4. package/dist/lib/back.d.ts +44 -0
  5. package/{lib → dist/lib}/back.js +111 -84
  6. package/dist/lib/common.d.ts +27 -0
  7. package/{lib → dist/lib}/common.js +80 -190
  8. package/dist/lib/debug.d.ts +9 -0
  9. package/dist/lib/debug.js +17 -0
  10. package/dist/lib/global_emitter.d.ts +11 -0
  11. package/dist/lib/global_emitter.js +13 -0
  12. package/dist/lib/handle-request.d.ts +2 -0
  13. package/{lib → dist/lib}/handle-request.js +24 -39
  14. package/dist/lib/intercept.d.ts +25 -0
  15. package/{lib → dist/lib}/intercept.js +81 -94
  16. package/dist/lib/interceptor.d.ts +44 -0
  17. package/{lib → dist/lib}/interceptor.js +223 -119
  18. package/dist/lib/interceptors/builtin.d.ts +3 -0
  19. package/dist/lib/interceptors/builtin.js +56 -0
  20. package/dist/lib/match_body.d.ts +1 -0
  21. package/{lib → dist/lib}/match_body.js +20 -27
  22. package/dist/lib/playback_interceptor.d.ts +8 -0
  23. package/{lib → dist/lib}/playback_interceptor.js +52 -62
  24. package/dist/lib/recorder.d.ts +13 -0
  25. package/{lib → dist/lib}/recorder.js +63 -92
  26. package/dist/lib/scope.d.ts +59 -0
  27. package/{lib → dist/lib}/scope.js +158 -87
  28. package/dist/lib/stringify.d.ts +24 -0
  29. package/dist/lib/stringify.js +50 -0
  30. package/dist/lib/utils/node/index.d.ts +4 -0
  31. package/dist/lib/utils/node/index.js +16 -0
  32. package/package.json +25 -22
  33. package/index.js +0 -55
  34. package/lib/create_response.js +0 -53
  35. package/lib/debug.js +0 -12
  36. package/lib/global_emitter.js +0 -5
  37. package/lib/interceptors/builtin.js +0 -67
  38. package/lib/interceptors/undici.js +0 -78
  39. package/lib/utils/node/index.js +0 -33
  40. package/types/index.d.ts +0 -319
package/index.js DELETED
@@ -1,55 +0,0 @@
1
- 'use strict'
2
-
3
- const back = require('./lib/back')
4
- const emitter = require('./lib/global_emitter')
5
- const {
6
- activate,
7
- isActive,
8
- isDone,
9
- isOn,
10
- pendingMocks,
11
- activeMocks,
12
- removeInterceptor,
13
- disableNetConnect,
14
- enableNetConnect,
15
- removeAll,
16
- abortPendingRequests,
17
- } = require('./lib/intercept')
18
- const recorder = require('./lib/recorder')
19
- const { Scope, load, loadDefs, define } = require('./lib/scope')
20
- const { getDecompressedGetBody } = require('./lib/utils/node')
21
-
22
- module.exports = (basePath, options) => new Scope(basePath, options)
23
-
24
- Object.assign(module.exports, {
25
- activate,
26
- isActive,
27
- isDone,
28
- pendingMocks,
29
- activeMocks,
30
- removeInterceptor,
31
- disableNetConnect,
32
- enableNetConnect,
33
- cleanAll: removeAll,
34
- abortPendingRequests,
35
- load,
36
- loadDefs,
37
- define,
38
- emitter,
39
- recorder: {
40
- rec: recorder.record,
41
- clear: recorder.clear,
42
- play: recorder.outputs,
43
- },
44
- restore: recorder.restore,
45
- back,
46
- getDecompressedGetBody,
47
- })
48
-
49
- // We always activate Nock on import, overriding the globals.
50
- // Setting the Back mode "activates" Nock by overriding the global entries in the `http/s` modules.
51
- // If Nock Back is configured, we need to honor that setting for backward compatibility,
52
- // otherwise we rely on Nock Back's default initializing side effect.
53
- if (isOn()) {
54
- back.setMode(process.env.NOCK_BACK_MODE || 'dryrun')
55
- }
@@ -1,53 +0,0 @@
1
- 'use strict'
2
-
3
- const { STATUS_CODES } = require('node:http')
4
-
5
- /**
6
- * Creates a Fetch API `Response` instance from the given
7
- * `http.IncomingMessage` instance.
8
- * Inspired by: https://github.com/mswjs/interceptors/blob/04152ed914f8041272b6e92ed374216b8177e1b2/src/interceptors/ClientRequest/utils/createResponse.ts#L8
9
- */
10
-
11
- /**
12
- * Response status codes for responses that cannot have body.
13
- * @see https://fetch.spec.whatwg.org/#statuses
14
- */
15
- const responseStatusCodesWithoutBody = [204, 205, 304]
16
-
17
- /**
18
- * @param {import('http').IncomingMessage} message
19
- * @param {AbortSignal} signal
20
- */
21
- function createResponse(message, signal) {
22
- const responseBodyOrNull = responseStatusCodesWithoutBody.includes(
23
- message.statusCode || 200,
24
- )
25
- ? null
26
- : new ReadableStream({
27
- start(controller) {
28
- message.on('data', chunk => controller.enqueue(chunk))
29
- message.on('end', () => controller.close())
30
- message.on('error', error => controller.error(error))
31
- signal.addEventListener('abort', () => message.destroy(signal.reason))
32
- },
33
- cancel() {
34
- message.destroy()
35
- },
36
- })
37
-
38
- const rawHeaders = new Headers()
39
- for (let i = 0; i < message.rawHeaders.length; i += 2) {
40
- rawHeaders.append(message.rawHeaders[i], message.rawHeaders[i + 1])
41
- }
42
-
43
- // @mswjs/interceptors supports rawHeaders. https://github.com/mswjs/interceptors/pull/598
44
- const response = new Response(responseBodyOrNull, {
45
- status: message.statusCode,
46
- statusText: message.statusMessage || STATUS_CODES[message.statusCode],
47
- headers: rawHeaders,
48
- })
49
-
50
- return response
51
- }
52
-
53
- module.exports = { createResponse }
package/lib/debug.js DELETED
@@ -1,12 +0,0 @@
1
- 'use strict'
2
-
3
- const { debuglog } = require('node:util')
4
-
5
- module.exports.back = debuglog('nock:back')
6
- module.exports.common = debuglog('nock:common')
7
- module.exports.intercept = debuglog('nock:intercept')
8
- module.exports.request_overrider = debuglog('nock:request_overrider')
9
- module.exports.playback_interceptor = debuglog('nock:playback_interceptor')
10
- module.exports.recorder = debuglog('nock:recorder')
11
- module.exports.socket = debuglog('nock:socket')
12
- module.exports.scopeDebuglog = namespace => debuglog(`nock:scope:${namespace}`)
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- const { EventEmitter } = require('node:events')
4
-
5
- module.exports = new EventEmitter()
@@ -1,67 +0,0 @@
1
- 'use strict'
2
-
3
- const http = require('node:http')
4
- const { getRawRequest, BatchInterceptor } = require('@mswjs/interceptors')
5
- const {
6
- default: nodeInterceptors,
7
- } = require('@mswjs/interceptors/presets/node')
8
- const common = require('../common')
9
- const handleRequest = require('../handle-request')
10
- const { arrayBuffer } = require('node:stream/consumers')
11
- const { getClientRequestBodyStream } = require('@mswjs/interceptors/utils/node')
12
- const { setDecompressedGetBody } = require('../utils/node')
13
-
14
- const interceptor = new BatchInterceptor({
15
- name: 'nock-interceptor',
16
- interceptors: nodeInterceptors,
17
- })
18
-
19
- function activate() {
20
- interceptor.apply()
21
-
22
- // Force msw to forward Nock's error instead of coerce it into 500 error
23
- interceptor.on('unhandledException', ({ controller, error }) => {
24
- controller.errorWith(error)
25
- })
26
- interceptor.on('request', async function ({ request, controller }) {
27
- if (request.headers.get('expect') === '100-continue') {
28
- // We currently do not support mocking 100-continue responses, so they are passed through for now.
29
- return
30
- }
31
- const rawRequest = getRawRequest(request)
32
-
33
- // If this is GET request with body, we need to read the body from the socket because Fetch API doesn't support this.
34
- const requestBodyBuffer = common.decompressRequestBody(
35
- rawRequest instanceof http.ClientRequest &&
36
- request.method === 'GET' &&
37
- request.headers.get('content-length') > 0
38
- ? await arrayBuffer(getClientRequestBodyStream(request))
39
- : await request.clone().arrayBuffer(),
40
- request.headers.get('content-encoding') || '',
41
- )
42
-
43
- const decompressedRequest = new Request(request, {
44
- body:
45
- requestBodyBuffer.length > 0 && request.method !== 'GET'
46
- ? requestBodyBuffer
47
- : undefined,
48
- })
49
- if (requestBodyBuffer.byteLength > 0 && request.method === 'GET') {
50
- setDecompressedGetBody(decompressedRequest, requestBodyBuffer)
51
- }
52
-
53
- const response = await handleRequest(decompressedRequest)
54
- if (response) {
55
- controller.respondWith(response)
56
- }
57
- })
58
- }
59
-
60
- function deactivate() {
61
- interceptor.dispose()
62
- }
63
-
64
- module.exports = {
65
- activate,
66
- deactivate,
67
- }
@@ -1,78 +0,0 @@
1
- 'use strict'
2
-
3
- // This file is loaded lazily after confirming undici is installed
4
- // eslint-disable-next-line n/no-unpublished-require
5
- const undici = require('undici')
6
- const handleRequest = require('../handle-request')
7
- const { URL } = require('node:url')
8
- const { convertHeadersToRaw } = require('../common')
9
-
10
- class NockClient extends undici.Client {
11
- dispatch(options, handler) {
12
- const url = new URL(options.path, options.origin)
13
- if (options.query) {
14
- url.search = new URLSearchParams(options.query).toString()
15
- }
16
-
17
- const decompressedRequest = new Request(url, {
18
- method: options.method,
19
- headers: options.headers,
20
- body: options.body,
21
- duplex: options.body ? 'half' : undefined,
22
- })
23
-
24
- handleRequest(decompressedRequest)
25
- .then(async response => {
26
- if (response) {
27
- handler.onConnect?.(err => handler.onError(err), null)
28
- handler.onHeaders?.(
29
- response.status,
30
- convertHeadersToRaw(response.headers),
31
- () => {},
32
- response.statusText,
33
- )
34
- handler.onData?.(Buffer.from(await response.arrayBuffer()))
35
- handler.onComplete?.([]) // responseTrailers
36
- } else {
37
- const dispatcher = options.dispatcher || {
38
- dispatch: super.dispatch.bind(this),
39
- }
40
- dispatcher.dispatch(options, handler)
41
- }
42
- })
43
- .catch(err => {
44
- handler.onError?.(err)
45
- })
46
- }
47
- }
48
-
49
- class NockAgent extends undici.Dispatcher {
50
- constructor(options) {
51
- super(options)
52
-
53
- this.agent = new undici.Agent({ options, factory: this.factory.bind(this) })
54
- this.originalOptions = options
55
- }
56
-
57
- dispatch(options, handler) {
58
- this.agent.dispatch(options, handler)
59
- }
60
-
61
- factory(origin) {
62
- const mockOptions = { ...this.originalOptions, agent: this }
63
- return new NockClient(origin, mockOptions)
64
- }
65
- }
66
-
67
- function activate() {
68
- undici.setGlobalDispatcher(new NockAgent())
69
- }
70
-
71
- function deactivate() {
72
- undici.setGlobalDispatcher(new undici.Agent())
73
- }
74
-
75
- module.exports = {
76
- activate,
77
- deactivate,
78
- }
@@ -1,33 +0,0 @@
1
- 'use strict'
2
- const { Readable } = require('node:stream')
3
-
4
- const kDecompressedGetBody = Symbol('kDecompressedGetBody')
5
-
6
- /**
7
- * @param {Request} request
8
- * @returns {ArrayBuffer}
9
- * Returns the request body stream of the given request.
10
- * @note This is only relevant in the context of `http.ClientRequest`.
11
- * This function will throw if the given `request` wasn't created based on
12
- * the `http.ClientRequest` instance.
13
- * You must rely on the web stream consumers for other request clients.
14
- */
15
- function getDecompressedGetBody(request) {
16
- if (request.method !== 'GET') {
17
- throw new Error('The request method must be GET')
18
- }
19
- return Readable.from(Reflect.get(request, kDecompressedGetBody))
20
- }
21
-
22
- /**
23
- * @param {Request} request
24
- * @param {ArrayBuffer} body
25
- */
26
- function setDecompressedGetBody(request, body) {
27
- Reflect.set(request, kDecompressedGetBody, Buffer.from(body))
28
- }
29
-
30
- module.exports = {
31
- getDecompressedGetBody,
32
- setDecompressedGetBody,
33
- }
package/types/index.d.ts DELETED
@@ -1,319 +0,0 @@
1
- // TypeScript Version: 5.0
2
-
3
- import { ReadStream } from 'fs'
4
- import { RequestOptions } from 'http'
5
- import { ParsedUrlQuery } from 'querystring'
6
- import { Readable } from 'stream'
7
- import { Url, URLSearchParams } from 'url'
8
-
9
- export = nock
10
-
11
- declare function nock(
12
- basePath: string | RegExp | URL,
13
- options?: nock.Options,
14
- ): nock.Scope
15
-
16
- declare namespace nock {
17
- function cleanAll(): void
18
- function activate(): void
19
- function isActive(): boolean
20
- function isDone(): boolean
21
- function pendingMocks(): string[]
22
- function activeMocks(): string[]
23
- function removeInterceptor(interceptor: Interceptor | ReqOptions): boolean
24
- function disableNetConnect(): void
25
- function enableNetConnect(
26
- matcher?: string | RegExp | ((host: string) => boolean),
27
- ): void
28
- function load(path: string): Scope[]
29
- function loadDefs(path: string): Definition[]
30
- function define(defs: Definition[]): Scope[]
31
- function restore(): void
32
- function abortPendingRequests(): void
33
-
34
- let back: Back
35
- let emitter: NockEmitter
36
- let recorder: Recorder
37
-
38
- type InterceptFunction = (
39
- uri: string | RegExp | { (uri: string): boolean },
40
- requestBody?: RequestBodyMatcher,
41
- interceptorOptions?: Options,
42
- ) => Interceptor
43
-
44
- // Essentially valid, decoded JSON with the addition of possible RegExp. TS doesn't currently have
45
- // a great way to represent JSON type data, this data matcher design is based off this comment.
46
- // https://github.com/microsoft/TypeScript/issues/1897#issuecomment-338650717
47
- type DataMatcher =
48
- | boolean
49
- | number
50
- | string
51
- | null
52
- | undefined
53
- | RegExp
54
- | DataMatcherArray
55
- | DataMatcherMap
56
- interface DataMatcherArray extends ReadonlyArray<DataMatcher> {}
57
- interface DataMatcherMap {
58
- [key: string]: DataMatcher
59
- }
60
-
61
- type RequestBodyMatcher =
62
- | string
63
- | Buffer
64
- | RegExp
65
- | DataMatcherArray
66
- | DataMatcherMap
67
- | { (body: any): boolean }
68
-
69
- type RequestHeaderMatcher =
70
- | string
71
- | RegExp
72
- | { (fieldValue: string): boolean }
73
-
74
- type Body = string | Record<string, any> // a string or decoded JSON
75
- type ReplyBody = Body | Buffer | ReadStream
76
-
77
- type ReplyHeaderFunction = (req: Request) => Promise<string | string[]>
78
- type ReplyHeaderValue = string | string[] | ReplyHeaderFunction
79
- type ReplyHeaders =
80
- | Record<string, ReplyHeaderValue>
81
- | Map<string, ReplyHeaderValue>
82
- | ReplyHeaderValue[]
83
-
84
- type StatusCode = number
85
- type ReplyFnResult =
86
- | readonly [StatusCode]
87
- | readonly [StatusCode, ReplyBody]
88
- | readonly [StatusCode, ReplyBody, ReplyHeaders]
89
-
90
- /**
91
- * Detailed mismatch information for the 'no match' event
92
- * @experimental This interface may change in future versions based on community feedback.
93
- */
94
- interface InterceptorMatchResult {
95
- interceptor: Interceptor
96
- reasons: string[]
97
- }
98
-
99
- /**
100
- * Enhanced global emitter with typed 'no match' event
101
- */
102
- interface NockEmitter extends NodeJS.EventEmitter {
103
- on(event: 'no match', listener: (req: Request) => void): this
104
- on(
105
- event: 'no match',
106
- listener: (
107
- req: Request,
108
- interceptorResults?: InterceptorMatchResult[],
109
- ) => void,
110
- ): this
111
- once(event: 'no match', listener: (req: Request) => void): this
112
- once(
113
- event: 'no match',
114
- listener: (
115
- req: Request,
116
- interceptorResults?: InterceptorMatchResult[],
117
- ) => void,
118
- ): this
119
- emit(
120
- event: 'no match',
121
- req: Request,
122
- interceptorResults?: InterceptorMatchResult[],
123
- ): boolean
124
- }
125
-
126
- interface Scope extends NodeJS.EventEmitter {
127
- get: InterceptFunction
128
- post: InterceptFunction
129
- put: InterceptFunction
130
- head: InterceptFunction
131
- patch: InterceptFunction
132
- merge: InterceptFunction
133
- delete: InterceptFunction
134
- options: InterceptFunction
135
-
136
- intercept: (
137
- uri: string | RegExp | { (uri: string): boolean },
138
- method: string,
139
- requestBody?: RequestBodyMatcher,
140
- options?: Options,
141
- ) => Interceptor
142
-
143
- defaultReplyHeaders(headers: ReplyHeaders): this
144
- matchHeader(name: string, value: RequestHeaderMatcher): this
145
- filteringPath(regex: RegExp, replace: string): this
146
- filteringPath(fn: (path: string) => string): this
147
- filteringRequestBody(regex: RegExp, replace: string): this
148
- filteringRequestBody(
149
- fn: (body: string, recordedBody: string) => string,
150
- ): this
151
-
152
- persist(flag?: boolean): this
153
- replyContentLength(): this
154
- replyDate(d?: Date): this
155
-
156
- done(): void
157
- isDone(): boolean
158
- pendingMocks(): string[]
159
- activeMocks(): string[]
160
- }
161
-
162
- interface Interceptor {
163
- query(
164
- matcher:
165
- | boolean
166
- | string
167
- | DataMatcherMap
168
- | URLSearchParams
169
- | { (parsedObj: ParsedUrlQuery): boolean },
170
- ): this
171
-
172
- // tslint (as of 5.16) is under the impression that the callback types can be unified,
173
- // however, doing so causes the params to lose their inherited types during use.
174
- // the order of the overrides is important for determining the param types in the replay fns.
175
- /* tslint:disable:unified-signatures */
176
- reply(
177
- replyFnWithCallback: (
178
- request: Request,
179
- callback: (
180
- err: NodeJS.ErrnoException | null,
181
- result: ReplyFnResult,
182
- ) => void,
183
- ) => void,
184
- ): Scope
185
- reply(
186
- replyFn: (request: Request) => ReplyFnResult | Promise<ReplyFnResult>,
187
- ): Scope
188
- reply(
189
- statusCode: StatusCode,
190
- replyBodyFnWithCallback: (
191
- request: Request,
192
- callback: (
193
- err: NodeJS.ErrnoException | null,
194
- result: ReplyBody,
195
- ) => void,
196
- ) => void,
197
- headers?: ReplyHeaders,
198
- ): Scope
199
- reply(
200
- statusCode: StatusCode,
201
- replyBodyFn: (request: Request) => ReplyBody | Promise<ReplyBody>,
202
- headers?: ReplyHeaders,
203
- ): Scope
204
- reply(responseCode?: StatusCode, body?: Body, headers?: ReplyHeaders): Scope
205
- /* tslint:enable:unified-signatures */
206
-
207
- replyWithError(errorMessage: string | object): Scope
208
- replyWithFile(
209
- statusCode: StatusCode,
210
- fileName: string,
211
- headers?: ReplyHeaders,
212
- ): Scope
213
-
214
- matchHeader(name: string, value: RequestHeaderMatcher): this
215
- basicAuth(options: { user: string; pass?: string }): this
216
-
217
- times(newCounter: number): this
218
- once(): this
219
- twice(): this
220
- thrice(): this
221
- optionally(flag?: boolean): this
222
-
223
- delay(opts: number): this
224
- }
225
-
226
- /**
227
- * Retrieves the decompressed body of a GET request.
228
- * This function handles the edge case of GET requests with a body.
229
- *
230
- * @param request - The Request object.
231
- * @returns A Promise resolving to the decompressed body.
232
- */
233
- function getDecompressedGetBody(request: Request): Promise<Readable>
234
-
235
- interface Options {
236
- allowUnmocked?: boolean
237
- reqheaders?: Record<string, RequestHeaderMatcher>
238
- badheaders?: string[]
239
- filteringScope?: { (scope: string): boolean }
240
- encodedQueryParams?: boolean
241
- }
242
-
243
- interface Recorder {
244
- rec(options?: boolean | RecorderOptions): void
245
- clear(): void
246
- play(): string[] | Definition[]
247
- }
248
-
249
- interface RecorderOptions {
250
- dont_print?: boolean
251
- output_objects?: boolean
252
- enable_reqheaders_recording?: boolean
253
- logging?: (content: string) => void
254
- use_separator?: boolean
255
- }
256
-
257
- interface Definition {
258
- scope: string | RegExp
259
- path: string | RegExp
260
- port?: number | string
261
- method?: string
262
- status?: number
263
- body?: RequestBodyMatcher
264
- reqheaders?: Record<string, RequestHeaderMatcher>
265
- response?: ReplyBody
266
- headers?: ReplyHeaders
267
- options?: Options
268
- }
269
-
270
- type BackMode = 'wild' | 'dryrun' | 'record' | 'update' | 'lockdown'
271
-
272
- interface Back {
273
- currentMode: BackMode
274
- fixtures: string
275
- setMode(mode: BackMode): void
276
-
277
- (fixtureName: string, nockedFn: (nockDone: () => void) => void): void
278
- (
279
- fixtureName: string,
280
- options: BackOptions,
281
- nockedFn: (nockDone: () => void) => void,
282
- ): void
283
- (
284
- fixtureName: string,
285
- options?: BackOptions,
286
- ): Promise<{
287
- nockDone: () => void
288
- context: BackContext
289
- }>
290
- }
291
-
292
- interface InterceptorSurface {
293
- method: string
294
- uri: string
295
- basePath: string
296
- path: string
297
- queries?: string
298
- counter: number
299
- body: string
300
- statusCode: number
301
- optional: boolean
302
- }
303
-
304
- interface BackContext {
305
- isLoaded: boolean
306
- scopes: Scope[]
307
- assertScopesFinished(): void
308
- query: InterceptorSurface[]
309
- }
310
-
311
- interface BackOptions {
312
- before?: (def: Definition) => void
313
- after?: (scope: Scope) => void
314
- afterRecord?: (defs: Definition[]) => Definition[] | string
315
- recorder?: RecorderOptions
316
- }
317
- }
318
-
319
- type ReqOptions = RequestOptions & { proto?: string }