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,16 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import querystring from 'node:querystring'
|
|
2
|
+
import * as common from './common.js'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const common = require('./common')
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {Request} request
|
|
9
|
-
* @param {*} spec
|
|
10
|
-
* @param {string} body - string or hex
|
|
11
|
-
* @returns
|
|
12
|
-
*/
|
|
13
|
-
module.exports = function matchBody(request, spec, body) {
|
|
4
|
+
export default function matchBody(request , spec , body ) {
|
|
14
5
|
if (spec instanceof RegExp) {
|
|
15
6
|
return spec.test(body)
|
|
16
7
|
}
|
|
@@ -26,6 +17,7 @@ module.exports = function matchBody(request, spec, body) {
|
|
|
26
17
|
|
|
27
18
|
// try to transform body to json or query string
|
|
28
19
|
let json
|
|
20
|
+
let matchBody = body
|
|
29
21
|
if (typeof spec === 'object' || typeof spec === 'function') {
|
|
30
22
|
try {
|
|
31
23
|
json = JSON.parse(body)
|
|
@@ -33,20 +25,20 @@ module.exports = function matchBody(request, spec, body) {
|
|
|
33
25
|
// not a valid JSON string
|
|
34
26
|
}
|
|
35
27
|
if (json !== undefined) {
|
|
36
|
-
|
|
28
|
+
matchBody = json
|
|
37
29
|
} else if (isUrlencoded) {
|
|
38
|
-
|
|
30
|
+
matchBody = querystring.parse(body)
|
|
39
31
|
}
|
|
40
32
|
}
|
|
41
33
|
|
|
42
34
|
if (typeof spec === 'function') {
|
|
43
|
-
return spec(
|
|
35
|
+
return spec(matchBody)
|
|
44
36
|
}
|
|
45
37
|
|
|
46
38
|
// strip line endings from both so that we get a match no matter what OS we are running on
|
|
47
39
|
// if Content-Type does not contain 'multipart'
|
|
48
|
-
if (!isMultipart && typeof
|
|
49
|
-
|
|
40
|
+
if (!isMultipart && typeof matchBody === 'string') {
|
|
41
|
+
matchBody = matchBody.replace(/\r?\n|\r/g, '')
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
if (!isMultipart && typeof spec === 'string') {
|
|
@@ -56,13 +48,18 @@ module.exports = function matchBody(request, spec, body) {
|
|
|
56
48
|
// Because the nature of URL encoding, all the values in the body must be cast to strings.
|
|
57
49
|
// dataEqual does strict checking, so we have to cast the non-regexp values in the spec too.
|
|
58
50
|
if (isUrlencoded) {
|
|
59
|
-
spec = mapValuesDeep(spec, val =>
|
|
51
|
+
spec = mapValuesDeep(spec, (val ) =>
|
|
52
|
+
val instanceof RegExp ? val : `${val}`,
|
|
53
|
+
)
|
|
60
54
|
}
|
|
61
55
|
|
|
62
|
-
return common.dataEqual(spec,
|
|
56
|
+
return common.dataEqual(spec, matchBody)
|
|
63
57
|
}
|
|
64
58
|
|
|
65
|
-
function mapValues(
|
|
59
|
+
function mapValues(
|
|
60
|
+
object ,
|
|
61
|
+
cb ,
|
|
62
|
+
) {
|
|
66
63
|
const keys = Object.keys(object)
|
|
67
64
|
const clonedObject = { ...object }
|
|
68
65
|
for (const key of keys) {
|
|
@@ -71,16 +68,12 @@ function mapValues(object, cb) {
|
|
|
71
68
|
return clonedObject
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
* Based on lodash issue discussion
|
|
76
|
-
* https://github.com/lodash/lodash/issues/1244
|
|
77
|
-
*/
|
|
78
|
-
function mapValuesDeep(obj, cb) {
|
|
71
|
+
function mapValuesDeep(obj , cb ) {
|
|
79
72
|
if (Array.isArray(obj)) {
|
|
80
|
-
return obj.map(v => mapValuesDeep(v, cb))
|
|
73
|
+
return obj.map((v ) => mapValuesDeep(v, cb))
|
|
81
74
|
}
|
|
82
75
|
if (common.isPlainObject(obj)) {
|
|
83
|
-
return mapValues(obj, v => mapValuesDeep(v, cb))
|
|
76
|
+
return mapValues(obj, (v ) => mapValuesDeep(v, cb))
|
|
84
77
|
}
|
|
85
78
|
return cb(obj)
|
|
86
79
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Interceptor } from './interceptor.ts';
|
|
2
|
+
declare function playbackInterceptor({ decompressedRequest, interceptor, requestBodyString, requestBodyIsUtf8Representable, }: {
|
|
3
|
+
decompressedRequest: Request;
|
|
4
|
+
requestBodyString: string;
|
|
5
|
+
requestBodyIsUtf8Representable: boolean;
|
|
6
|
+
interceptor: Interceptor;
|
|
7
|
+
}): Promise<import("undici-types").Response>;
|
|
8
|
+
export { playbackInterceptor };
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function parseFullReplyResult(fullReplyResult) {
|
|
1
|
+
|
|
2
|
+
import { STATUS_CODES } from 'node:http'
|
|
3
|
+
import stream from 'node:stream'
|
|
4
|
+
import util from 'node:util'
|
|
5
|
+
import { playback_interceptor as debug } from './debug.js'
|
|
6
|
+
import * as common from './common.js'
|
|
7
|
+
import { FetchResponse } from '@mswjs/interceptors'
|
|
8
|
+
|
|
9
|
+
function parseFullReplyResult(fullReplyResult ) {
|
|
11
10
|
debug('full response from callback result: %j', fullReplyResult)
|
|
12
11
|
|
|
13
12
|
if (!Array.isArray(fullReplyResult)) {
|
|
@@ -32,23 +31,18 @@ function parseFullReplyResult(fullReplyResult) {
|
|
|
32
31
|
return [status, body, rawHeaders]
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
* Determine which of the default headers should be added to the response.
|
|
37
|
-
*
|
|
38
|
-
* Don't include any defaults whose case-insensitive keys are already on the response.
|
|
39
|
-
*/
|
|
40
|
-
function selectDefaultHeaders(existingHeaders, defaultHeaders) {
|
|
34
|
+
function selectDefaultHeaders(existingHeaders , defaultHeaders ) {
|
|
41
35
|
if (!defaultHeaders.length) {
|
|
42
36
|
return [] // return early if we don't need to bother
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
const definedHeaders = new Set()
|
|
46
|
-
const result
|
|
40
|
+
const result = []
|
|
47
41
|
|
|
48
|
-
common.forEachHeader(existingHeaders, (_, fieldName) => {
|
|
42
|
+
common.forEachHeader(existingHeaders, (_ , fieldName ) => {
|
|
49
43
|
definedHeaders.add(fieldName.toLowerCase())
|
|
50
44
|
})
|
|
51
|
-
common.forEachHeader(defaultHeaders, (value, fieldName) => {
|
|
45
|
+
common.forEachHeader(defaultHeaders, (value , fieldName ) => {
|
|
52
46
|
if (!definedHeaders.has(fieldName.toLowerCase())) {
|
|
53
47
|
result.push([fieldName, value])
|
|
54
48
|
}
|
|
@@ -59,7 +53,9 @@ function selectDefaultHeaders(existingHeaders, defaultHeaders) {
|
|
|
59
53
|
|
|
60
54
|
// Presents a list of Buffers as a Readable
|
|
61
55
|
class ReadableBuffers extends stream.Readable {
|
|
62
|
-
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
constructor(buffers ) {
|
|
63
59
|
super()
|
|
64
60
|
|
|
65
61
|
this.buffers = buffers
|
|
@@ -75,7 +71,7 @@ class ReadableBuffers extends stream.Readable {
|
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
function convertBodyToStream(body) {
|
|
74
|
+
function convertBodyToStream(body ) {
|
|
79
75
|
if (common.isStream(body)) {
|
|
80
76
|
return body
|
|
81
77
|
}
|
|
@@ -95,21 +91,17 @@ function convertBodyToStream(body) {
|
|
|
95
91
|
return new ReadableBuffers([Buffer.from(body)])
|
|
96
92
|
}
|
|
97
93
|
|
|
98
|
-
/**
|
|
99
|
-
* Play back an interceptor using the given request and mock response.
|
|
100
|
-
*
|
|
101
|
-
* @param {Object} param0
|
|
102
|
-
* @param {Request} param0.decompressedRequest
|
|
103
|
-
* @param {string} param0.requestBodyString
|
|
104
|
-
* @param {boolean} param0.requestBodyIsUtf8Representable
|
|
105
|
-
* @param {import('./interceptor').Interceptor} param0.interceptor
|
|
106
|
-
*/
|
|
107
94
|
async function playbackInterceptor({
|
|
108
95
|
decompressedRequest,
|
|
109
96
|
interceptor,
|
|
110
97
|
requestBodyString,
|
|
111
98
|
requestBodyIsUtf8Representable,
|
|
112
|
-
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
) {
|
|
113
105
|
const { logger } = interceptor.scope
|
|
114
106
|
interceptor.scope.emit(
|
|
115
107
|
'request',
|
|
@@ -139,14 +131,14 @@ async function playbackInterceptor({
|
|
|
139
131
|
let fn = interceptor.replyFunction
|
|
140
132
|
if (fn.length === 2) {
|
|
141
133
|
// Handle the case of an async reply function, the third parameter being the callback.
|
|
142
|
-
fn = util.promisify(fn)
|
|
134
|
+
fn = util.promisify(fn)
|
|
143
135
|
}
|
|
144
136
|
|
|
145
137
|
// At this point `fn` is either a synchronous function or a promise-returning function;
|
|
146
138
|
// wrapping in `Promise.resolve` makes it into a promise either way.
|
|
147
|
-
return Promise.resolve(fn.call(interceptor, decompressedRequest))
|
|
139
|
+
return Promise.resolve((fn ).call(interceptor, decompressedRequest))
|
|
148
140
|
.then(continueWithResponseBody)
|
|
149
|
-
.catch(err => {
|
|
141
|
+
.catch((err ) => {
|
|
150
142
|
throw err
|
|
151
143
|
})
|
|
152
144
|
}
|
|
@@ -154,35 +146,35 @@ async function playbackInterceptor({
|
|
|
154
146
|
else if (interceptor.fullReplyFunction) {
|
|
155
147
|
let fn = interceptor.fullReplyFunction
|
|
156
148
|
if (fn.length === 2) {
|
|
157
|
-
fn = util.promisify(fn)
|
|
149
|
+
fn = util.promisify(fn)
|
|
158
150
|
}
|
|
159
151
|
|
|
160
|
-
return Promise.resolve(fn.call(interceptor, decompressedRequest))
|
|
152
|
+
return Promise.resolve((fn ).call(interceptor, decompressedRequest))
|
|
161
153
|
.then(continueWithFullResponse)
|
|
162
|
-
.catch(err => {
|
|
154
|
+
.catch((err ) => {
|
|
163
155
|
throw err
|
|
164
156
|
})
|
|
165
157
|
}
|
|
166
158
|
|
|
167
159
|
if (
|
|
168
|
-
common.isContentEncoded(interceptor.headers) &&
|
|
160
|
+
common.isContentEncoded(interceptor.headers || {}) &&
|
|
169
161
|
!common.isStream(interceptor.body)
|
|
170
162
|
) {
|
|
171
163
|
// If the content is encoded we know that the response body *must* be an array
|
|
172
164
|
// of response buffers which should be mocked one by one.
|
|
173
|
-
// (otherwise decompressions after the first one fails as unzip expects to receive
|
|
174
|
-
// buffer by buffer and not one single merged buffer)
|
|
175
165
|
const bufferData = Array.isArray(interceptor.body)
|
|
176
166
|
? interceptor.body
|
|
177
167
|
: [interceptor.body]
|
|
178
|
-
const responseBuffers = bufferData.map(data =>
|
|
168
|
+
const responseBuffers = bufferData.map((data ) =>
|
|
169
|
+
Buffer.from(data, 'hex'),
|
|
170
|
+
)
|
|
179
171
|
const responseBody = new ReadableBuffers(responseBuffers)
|
|
180
172
|
return continueWithResponseBody(responseBody)
|
|
181
173
|
}
|
|
182
174
|
|
|
183
175
|
// If we get to this point, the body is either a string or an object that
|
|
184
176
|
// will eventually be JSON stringified.
|
|
185
|
-
let responseBody
|
|
177
|
+
let responseBody = interceptor.body
|
|
186
178
|
|
|
187
179
|
// If the request was not UTF8-representable then we assume that the
|
|
188
180
|
// response won't be either. In that case we send the response as a Buffer
|
|
@@ -194,28 +186,26 @@ async function playbackInterceptor({
|
|
|
194
186
|
// Creating buffers does not necessarily throw errors; check for difference in size.
|
|
195
187
|
if (
|
|
196
188
|
!responseBody ||
|
|
197
|
-
(interceptor.body.length > 0 && responseBody.length === 0)
|
|
189
|
+
((interceptor.body ).length > 0 && responseBody.length === 0)
|
|
198
190
|
) {
|
|
199
191
|
// We fallback on constructing buffer from utf8 representation of the body.
|
|
200
|
-
responseBody = Buffer.from(interceptor.body, 'utf8')
|
|
192
|
+
responseBody = Buffer.from(interceptor.body , 'utf8')
|
|
201
193
|
}
|
|
202
194
|
}
|
|
203
195
|
|
|
204
196
|
return continueWithResponseBody(responseBody)
|
|
205
197
|
|
|
206
|
-
function continueWithFullResponse(fullReplyResult) {
|
|
198
|
+
function continueWithFullResponse(fullReplyResult ) {
|
|
207
199
|
const [status, responseBody, rawHeaders] =
|
|
208
200
|
parseFullReplyResult(fullReplyResult)
|
|
209
201
|
return continueWithResponseBody(responseBody, status, rawHeaders)
|
|
210
202
|
}
|
|
211
203
|
|
|
212
|
-
async function prepareResponseHeaders(body, responseHeaders) {
|
|
204
|
+
async function prepareResponseHeaders(body , responseHeaders ) {
|
|
213
205
|
const defaultHeaders = [...interceptor.scope._defaultReplyHeaders]
|
|
214
|
-
const rawHeaders
|
|
206
|
+
const rawHeaders = []
|
|
215
207
|
|
|
216
208
|
// Include a JSON content type when JSON.stringify is called on the body.
|
|
217
|
-
// This is a convenience added by Nock that has no analog in Node. It's added to the
|
|
218
|
-
// defaults, so it will be ignored if the caller explicitly provided the header already.
|
|
219
209
|
const isJSON =
|
|
220
210
|
body !== undefined &&
|
|
221
211
|
typeof body !== 'string' &&
|
|
@@ -226,15 +216,15 @@ async function playbackInterceptor({
|
|
|
226
216
|
defaultHeaders.push('Content-Type', 'application/json')
|
|
227
217
|
}
|
|
228
218
|
common.forEachHeader(
|
|
229
|
-
[...interceptor.rawHeaders, ...responseHeaders],
|
|
230
|
-
(value, fieldName) => {
|
|
219
|
+
[...(interceptor.rawHeaders || []), ...responseHeaders],
|
|
220
|
+
(value , fieldName ) => {
|
|
231
221
|
rawHeaders.push([fieldName, value])
|
|
232
222
|
},
|
|
233
223
|
)
|
|
234
224
|
|
|
235
225
|
rawHeaders.push(
|
|
236
226
|
...selectDefaultHeaders(
|
|
237
|
-
[...interceptor.rawHeaders, ...responseHeaders],
|
|
227
|
+
[...(interceptor.rawHeaders || []), ...responseHeaders],
|
|
238
228
|
defaultHeaders,
|
|
239
229
|
),
|
|
240
230
|
)
|
|
@@ -244,7 +234,7 @@ async function playbackInterceptor({
|
|
|
244
234
|
|
|
245
235
|
// Evaluate functional headers.
|
|
246
236
|
if (typeof value === 'function') {
|
|
247
|
-
rawHeaders[i][1] = await value(decompressedRequest)
|
|
237
|
+
rawHeaders[i][1] = await value(decompressedRequest, body)
|
|
248
238
|
}
|
|
249
239
|
}
|
|
250
240
|
|
|
@@ -252,9 +242,9 @@ async function playbackInterceptor({
|
|
|
252
242
|
}
|
|
253
243
|
|
|
254
244
|
async function continueWithResponseBody(
|
|
255
|
-
rawBody,
|
|
256
|
-
fullResponseStatus,
|
|
257
|
-
fullResponseRawHeaders
|
|
245
|
+
rawBody ,
|
|
246
|
+
fullResponseStatus ,
|
|
247
|
+
fullResponseRawHeaders = [],
|
|
258
248
|
) {
|
|
259
249
|
const headers = await prepareResponseHeaders(
|
|
260
250
|
rawBody,
|
|
@@ -268,7 +258,7 @@ async function playbackInterceptor({
|
|
|
268
258
|
const readable = new stream.Readable({
|
|
269
259
|
read() {},
|
|
270
260
|
})
|
|
271
|
-
bodyAsStream.on('data', function (chunk) {
|
|
261
|
+
bodyAsStream.on('data', function (chunk ) {
|
|
272
262
|
readable.push(chunk)
|
|
273
263
|
})
|
|
274
264
|
bodyAsStream.on('end', function () {
|
|
@@ -277,18 +267,18 @@ async function playbackInterceptor({
|
|
|
277
267
|
interceptor.scope.emit('replied', decompressedRequest, interceptor)
|
|
278
268
|
}, interceptor.delayBodyInMs)
|
|
279
269
|
})
|
|
280
|
-
bodyAsStream.on('error', function (err) {
|
|
270
|
+
bodyAsStream.on('error', function (err ) {
|
|
281
271
|
readable.emit('error', err)
|
|
282
272
|
})
|
|
283
273
|
|
|
284
274
|
const status = interceptor.statusCode || fullResponseStatus
|
|
285
|
-
const hasBody = FetchResponse.isResponseWithBody(status)
|
|
275
|
+
const hasBody = FetchResponse.isResponseWithBody(status )
|
|
286
276
|
return new Response(hasBody ? readable : null, {
|
|
287
|
-
status,
|
|
288
|
-
statusText: STATUS_CODES[status],
|
|
277
|
+
status: status ,
|
|
278
|
+
statusText: STATUS_CODES[status ],
|
|
289
279
|
headers,
|
|
290
280
|
})
|
|
291
281
|
}
|
|
292
282
|
}
|
|
293
283
|
|
|
294
|
-
|
|
284
|
+
export { playbackInterceptor }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Definition } from './scope.ts';
|
|
2
|
+
export interface RecorderOptions {
|
|
3
|
+
dont_print?: boolean;
|
|
4
|
+
output_objects?: boolean;
|
|
5
|
+
enable_reqheaders_recording?: boolean;
|
|
6
|
+
logging?: (content: string) => void;
|
|
7
|
+
use_separator?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function record(recOptions?: boolean | RecorderOptions): void;
|
|
10
|
+
declare function restore(): void;
|
|
11
|
+
declare function clear(): void;
|
|
12
|
+
declare function outputs(): string[] | Definition[];
|
|
13
|
+
export { record, outputs, restore, clear };
|
|
@@ -1,41 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import { recorder as debug } from './debug.js'
|
|
12
|
+
import querystring from 'node:querystring'
|
|
13
|
+
import { inspect } from 'node:util'
|
|
14
|
+
|
|
15
|
+
import * as common from './common.js'
|
|
16
|
+
import { restoreOverriddenClientRequest } from './intercept.js'
|
|
17
|
+
import { BatchInterceptor } from '@mswjs/interceptors'
|
|
18
|
+
import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest'
|
|
19
|
+
import { FetchInterceptor } from '@mswjs/interceptors/fetch'
|
|
20
|
+
|
|
13
21
|
const SEPARATOR = '\n<<<<<<-- cut here -->>>>>>\n'
|
|
14
22
|
let recordingInProgress = false
|
|
15
|
-
let
|
|
23
|
+
let _outputs = []
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
const interceptor = new BatchInterceptor({
|
|
26
|
+
name: 'intercept',
|
|
27
|
+
interceptors: [new ClientRequestInterceptor(), new FetchInterceptor()],
|
|
28
|
+
})
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
* @param {URL} url
|
|
23
|
-
*/
|
|
24
|
-
function getScope(url) {
|
|
30
|
+
function getScope(url ) {
|
|
25
31
|
return common.normalizeOrigin(url)
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
function getMethod(request) {
|
|
34
|
+
function getMethod(request ) {
|
|
29
35
|
return request.method || 'GET'
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
function getBodyFromChunks(chunks, headers) {
|
|
38
|
+
function getBodyFromChunks(chunks , headers ) {
|
|
33
39
|
// If we have headers and there is content-encoding it means that the body
|
|
34
40
|
// shouldn't be merged but instead persisted as an array of hex strings so
|
|
35
41
|
// that the response chunks can be mocked one by one.
|
|
36
42
|
if (headers && common.isContentEncoded(headers)) {
|
|
37
43
|
return {
|
|
38
|
-
body: chunks.map(chunk => chunk.toString('hex')),
|
|
44
|
+
body: chunks.map((chunk ) => chunk.toString('hex')),
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
@@ -67,11 +73,10 @@ function getBodyFromChunks(chunks, headers) {
|
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
async function generateRequestAndResponseObject(request, response) {
|
|
76
|
+
async function generateRequestAndResponseObject(
|
|
77
|
+
request ,
|
|
78
|
+
response ,
|
|
79
|
+
) {
|
|
75
80
|
const { body, isUtf8Representable } = getBodyFromChunks(
|
|
76
81
|
[Buffer.from(await response.arrayBuffer())],
|
|
77
82
|
Object.fromEntries(response.headers.entries()),
|
|
@@ -94,22 +99,20 @@ async function generateRequestAndResponseObject(request, response) {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
async function generateRequestAndResponse(request, response) {
|
|
102
|
+
async function generateRequestAndResponse(
|
|
103
|
+
request ,
|
|
104
|
+
response ,
|
|
105
|
+
) {
|
|
102
106
|
const url = new URL(request.url)
|
|
103
107
|
const requestBody = getBodyFromChunks([
|
|
104
108
|
Buffer.from(await request.arrayBuffer()),
|
|
105
109
|
]).body
|
|
106
110
|
const responseBody = getBodyFromChunks(
|
|
107
111
|
[Buffer.from(await response.arrayBuffer())],
|
|
108
|
-
response.headers,
|
|
112
|
+
response.headers ,
|
|
109
113
|
).body
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
const encodedQueryObj = {}
|
|
115
|
+
const encodedQueryObj = {}
|
|
113
116
|
|
|
114
117
|
for (const [key, value] of Object.entries(
|
|
115
118
|
querystring.parse(url.searchParams.toString()),
|
|
@@ -122,7 +125,7 @@ async function generateRequestAndResponse(request, response) {
|
|
|
122
125
|
encodedQueryObj[formattedPair[0]] = formattedPair[1]
|
|
123
126
|
}
|
|
124
127
|
|
|
125
|
-
const lines
|
|
128
|
+
const lines = []
|
|
126
129
|
|
|
127
130
|
// We want a leading newline.
|
|
128
131
|
lines.push('')
|
|
@@ -151,7 +154,7 @@ async function generateRequestAndResponse(request, response) {
|
|
|
151
154
|
lines.push(` .query(${JSON.stringify(encodedQueryObj)})`)
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
const statusCode = response.status
|
|
157
|
+
const statusCode = String(response.status)
|
|
155
158
|
const stringifiedResponseBody = JSON.stringify(responseBody)
|
|
156
159
|
const headers = inspect(Object.fromEntries(response.headers.entries()))
|
|
157
160
|
lines.push(` .reply(${statusCode}, ${stringifiedResponseBody}, ${headers});`)
|
|
@@ -174,7 +177,7 @@ const defaultRecordOptions = {
|
|
|
174
177
|
use_separator: true,
|
|
175
178
|
}
|
|
176
179
|
|
|
177
|
-
function record(recOptions) {
|
|
180
|
+
function record(recOptions ) {
|
|
178
181
|
// Trying to start recording with recording already in progress implies an error
|
|
179
182
|
// in the recording configuration (double recording makes no sense and used to lead
|
|
180
183
|
// to duplicates in output)
|
|
@@ -206,7 +209,10 @@ function record(recOptions) {
|
|
|
206
209
|
use_separator: useSeparator,
|
|
207
210
|
} = recOptions
|
|
208
211
|
|
|
209
|
-
debug(
|
|
212
|
+
debug(
|
|
213
|
+
String(thisRecordingId),
|
|
214
|
+
'restoring overridden requests before new overrides',
|
|
215
|
+
)
|
|
210
216
|
// To preserve backward compatibility (starting recording wasn't throwing if nock was already active)
|
|
211
217
|
// we restore any requests that may have been overridden by other parts of nock (e.g. intercept)
|
|
212
218
|
// NOTE: This is hacky as hell but it keeps the backward compatibility *and* allows correct
|
|
@@ -216,49 +222,16 @@ function record(recOptions) {
|
|
|
216
222
|
restoreOverriddenClientRequest()
|
|
217
223
|
|
|
218
224
|
// We override the requests so that we can save information on them before executing.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
async function ({ request, response }) {
|
|
224
|
-
await recordResponse(request, response)
|
|
225
|
-
},
|
|
226
|
-
)
|
|
227
|
-
fetchRequestInterceptor.on(
|
|
228
|
-
'response',
|
|
229
|
-
async function ({ request, response }) {
|
|
230
|
-
// fetch decompresses the body automatically, so we need to recompress it
|
|
231
|
-
const codings =
|
|
232
|
-
response.headers
|
|
233
|
-
.get('content-encoding')
|
|
234
|
-
?.toLowerCase()
|
|
235
|
-
.split(',')
|
|
236
|
-
.map(c => c.trim()) || []
|
|
237
|
-
|
|
238
|
-
let body = await response.arrayBuffer()
|
|
239
|
-
for (const coding of codings) {
|
|
240
|
-
if (coding === 'gzip') {
|
|
241
|
-
body = gzipSync(body)
|
|
242
|
-
} else if (coding === 'deflate') {
|
|
243
|
-
body = deflateSync(body)
|
|
244
|
-
} else if (coding === 'br') {
|
|
245
|
-
body = brotliCompressSync(body)
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
await recordResponse(request, new Response(body, response))
|
|
250
|
-
},
|
|
251
|
-
)
|
|
225
|
+
interceptor.apply()
|
|
226
|
+
interceptor.on('response', async function ({ request, response }) {
|
|
227
|
+
await recordResponse(request, response)
|
|
228
|
+
})
|
|
252
229
|
|
|
253
|
-
|
|
254
|
-
* @param {Request} mswRequest
|
|
255
|
-
* @param {Response} mswResponse
|
|
256
|
-
*/
|
|
257
|
-
async function recordResponse(mswRequest, mswResponse) {
|
|
230
|
+
async function recordResponse(mswRequest , mswResponse ) {
|
|
258
231
|
const request = mswRequest.clone()
|
|
259
232
|
const response = mswResponse.clone()
|
|
260
233
|
debug(
|
|
261
|
-
thisRecordingId,
|
|
234
|
+
String(thisRecordingId),
|
|
262
235
|
request.url.split(':', 1)[0],
|
|
263
236
|
'intercepted request ended',
|
|
264
237
|
)
|
|
@@ -279,7 +252,7 @@ function record(recOptions) {
|
|
|
279
252
|
const generateFn = outputObjects
|
|
280
253
|
? generateRequestAndResponseObject
|
|
281
254
|
: generateRequestAndResponse
|
|
282
|
-
let out
|
|
255
|
+
let out = await generateFn(request, response)
|
|
283
256
|
|
|
284
257
|
debug('out:', out)
|
|
285
258
|
|
|
@@ -296,16 +269,16 @@ function record(recOptions) {
|
|
|
296
269
|
return
|
|
297
270
|
}
|
|
298
271
|
|
|
299
|
-
|
|
272
|
+
_outputs.push(out)
|
|
300
273
|
|
|
301
274
|
if (!dontPrint) {
|
|
302
275
|
if (useSeparator) {
|
|
303
276
|
if (typeof out !== 'string') {
|
|
304
277
|
out = JSON.stringify(out, null, 2)
|
|
305
278
|
}
|
|
306
|
-
logging(SEPARATOR + out + SEPARATOR)
|
|
279
|
+
;(logging )(SEPARATOR + out + SEPARATOR)
|
|
307
280
|
} else {
|
|
308
|
-
logging(out)
|
|
281
|
+
;(logging )(out)
|
|
309
282
|
}
|
|
310
283
|
}
|
|
311
284
|
|
|
@@ -316,23 +289,21 @@ function record(recOptions) {
|
|
|
316
289
|
// Restore *all* the overridden http/https modules' properties.
|
|
317
290
|
function restore() {
|
|
318
291
|
debug(
|
|
319
|
-
currentRecordingId,
|
|
292
|
+
String(currentRecordingId),
|
|
320
293
|
'restoring all the overridden http/https properties',
|
|
321
294
|
)
|
|
322
295
|
|
|
323
|
-
|
|
324
|
-
fetchRequestInterceptor.dispose()
|
|
296
|
+
interceptor.dispose()
|
|
325
297
|
restoreOverriddenClientRequest()
|
|
326
298
|
recordingInProgress = false
|
|
327
299
|
}
|
|
328
300
|
|
|
329
301
|
function clear() {
|
|
330
|
-
|
|
302
|
+
_outputs = []
|
|
331
303
|
}
|
|
332
304
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
outputs: () => outputs,
|
|
336
|
-
restore,
|
|
337
|
-
clear,
|
|
305
|
+
function outputs() {
|
|
306
|
+
return _outputs
|
|
338
307
|
}
|
|
308
|
+
|
|
309
|
+
export { record, outputs, restore, clear }
|