Skip to content

Commit

Permalink
Rebase record_unmatched functionality (nock#1235) (nock#2038)
Browse files Browse the repository at this point in the history
  • Loading branch information
guerrerocarlos authored and irfan798 committed Feb 17, 2024
1 parent 4162fa8 commit 70caa2e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 75 deletions.
14 changes: 11 additions & 3 deletions lib/back.js
Expand Up @@ -48,8 +48,8 @@ function Back(fixtureName, options, nockedFn) {
if (!Back.fixtures) {
throw new Error(
'Back requires nock.back.fixtures to be set\n' +
'Ex:\n' +
"\trequire(nock).back.fixtures = '/path/to/fixtures/'",
'Ex:\n' +
"\trequire(nock).back.fixtures = '/path/to/fixtures/'"
)
}

Expand Down Expand Up @@ -135,10 +135,12 @@ const record = {
recorder.clear()
cleanAll()
activate()
disableNetConnect()
},

start: function (fixture, options) {
if(!(options && options.recorder && options.recorder.record_unmatched)) {
disableNetConnect()
}
if (!fs) {
throw new Error('no fs')
}
Expand All @@ -165,6 +167,9 @@ const record = {
outputs = options.afterRecord(outputs)
}

if (fs.existsSync(fixture)) {
outputs = JSON.parse(fs.readFileSync(fixture)).concat(outputs)
}
outputs =
typeof outputs === 'string' ? outputs : JSON.stringify(outputs, null, 4)
debug('recorder outputs:', outputs)
Expand Down Expand Up @@ -270,6 +275,9 @@ function load(fixture, options) {
context.isLoaded = true
}

if(options && options.enableRecording) {
context.isLoaded = true
}
return context
}

Expand Down
101 changes: 53 additions & 48 deletions lib/common.js
Expand Up @@ -27,12 +27,12 @@ function normalizeRequestOptions(options) {
options.host = `${options.hostname || 'localhost'}:${options.port}`
debug('options.host in the end: %j', options.host)

/// lowercase host names
;['hostname', 'host'].forEach(function (attr) {
if (options[attr]) {
options[attr] = options[attr].toLowerCase()
}
})
/// lowercase host names
;['hostname', 'host'].forEach(function (attr) {
if (options[attr]) {
options[attr] = options[attr].toLowerCase()
}
})

return options
}
Expand All @@ -52,7 +52,7 @@ function isUtf8Representable(buffer) {

// Array where all information about all the overridden requests are held.
let requestOverrides = {}

let secondLayer
/**
* Overrides the current `request` function of `http` and `https` modules with
* our own version which intercepts issues HTTP/HTTPS requests and forwards them
Expand All @@ -66,47 +66,52 @@ let requestOverrides = {}
*/
function overrideRequests(newRequest) {
debug('overriding requests')
;['http', 'https'].forEach(function (proto) {
debug('- overriding request for', proto)

const moduleName = proto // 1 to 1 match of protocol and module is fortunate :)
const module = require(proto)
const overriddenRequest = module.request
const overriddenGet = module.get

if (requestOverrides[moduleName]) {
throw new Error(
`Module's request already overridden for ${moduleName} protocol.`,
)
}
;['http', 'https'].forEach(function (proto) {
debug('- overriding request for', proto)

const moduleName = proto // 1 to 1 match of protocol and module is fortunate :)
const module = {
http: require('http'),
https: require('https'),
}[moduleName]
const overriddenRequest = module.request
const overriddenGet = module.get

if (requestOverrides[moduleName]) {
debug('set recorder as second layer')
secondLayer = newRequest
} else {
// Store the properties of the overridden request so that it can be restored later on.
requestOverrides[moduleName] = {
module,
request: overriddenRequest,
get: overriddenGet,
}
// https://nodejs.org/api/http.html#http_http_request_url_options_callback
module.request = function (input, options, callback) {
return newRequest(proto, overriddenRequest.bind(module), [
input,
options,
callback,
secondLayer,
])
}
// https://nodejs.org/api/http.html#http_http_get_options_callback
module.get = function (input, options, callback) {
const req = newRequest(proto, overriddenGet.bind(module), [
input,
options,
callback,
secondLayer,
])
req.end()
return req
}
}

// Store the properties of the overridden request so that it can be restored later on.
requestOverrides[moduleName] = {
module,
request: overriddenRequest,
get: overriddenGet,
}
// https://nodejs.org/api/http.html#http_http_request_url_options_callback
module.request = function (input, options, callback) {
return newRequest(proto, overriddenRequest.bind(module), [
input,
options,
callback,
])
}
// https://nodejs.org/api/http.html#http_http_get_options_callback
module.get = function (input, options, callback) {
const req = newRequest(proto, overriddenGet.bind(module), [
input,
options,
callback,
])
req.end()
return req
}

debug('- overridden request for', proto)
})
debug('- overridden request for', proto)
})
}

/**
Expand Down Expand Up @@ -493,7 +498,7 @@ function isStream(obj) {
* Taken from the beginning of the native `ClientRequest`.
* https://github.com/nodejs/node/blob/908292cf1f551c614a733d858528ffb13fb3a524/lib/_http_client.js#L68
*/
function normalizeClientRequestArgs(input, options, cb) {
function normalizeClientRequestArgs(input, options, cb, secondLayer) {
if (typeof input === 'string') {
input = urlToOptions(new url.URL(input))
} else if (input instanceof url.URL) {
Expand All @@ -511,7 +516,7 @@ function normalizeClientRequestArgs(input, options, cb) {
options = Object.assign(input || {}, options)
}

return { options, callback: cb }
return { options, callback: cb, secondLayer }
}

/**
Expand Down
8 changes: 6 additions & 2 deletions lib/intercept.js
Expand Up @@ -376,7 +376,7 @@ function activate() {
common.overrideRequests(function (proto, overriddenRequest, args) {
// NOTE: overriddenRequest is already bound to its module.

const { options, callback } = common.normalizeClientRequestArgs(...args)
const { options, callback, secondLayer } = common.normalizeClientRequestArgs(...args)

if (Object.keys(options).length === 0) {
// As weird as it is, it's possible to call `http.request` without
Expand Down Expand Up @@ -427,7 +427,11 @@ function activate() {
} else {
globalEmitter.emit('no match', options)
if (isOff() || isEnabledForNetConnect(options)) {
return overriddenRequest(options, callback)
if (secondLayer) {
return secondLayer(proto, overriddenRequest, options, callback)
} else {
return overriddenRequest(options, callback);
}
} else {
const error = new NetConnectNotAllowedError(options.host, options.path)
return new ErroringClientRequest(error)
Expand Down
17 changes: 10 additions & 7 deletions lib/recorder.js
Expand Up @@ -171,6 +171,7 @@ const defaultRecordOptions = {
logging: console.log, // eslint-disable-line no-console
output_objects: false,
use_separator: true,
record_unmatched: false,
}

function record(recOptions) {
Expand Down Expand Up @@ -206,13 +207,15 @@ function record(recOptions) {
} = recOptions

debug(thisRecordingId, 'restoring overridden requests before new overrides')
// To preserve backward compatibility (starting recording wasn't throwing if nock was already active)
// we restore any requests that may have been overridden by other parts of nock (e.g. intercept)
// NOTE: This is hacky as hell but it keeps the backward compatibility *and* allows correct
// behavior in the face of other modules also overriding ClientRequest.
common.restoreOverriddenRequests()
// We restore ClientRequest as it messes with recording of modules that also override ClientRequest (e.g. xhr2)
restoreOverriddenClientRequest()
if(!recOptions.record_unmatched) {
// To preserve backward compatibility (starting recording wasn't throwing if nock was already active)
// we restore any requests that may have been overridden by other parts of nock (e.g. intercept)
// NOTE: This is hacky as hell but it keeps the backward compatibility *and* allows correct
// behavior in the face of other modules also overriding ClientRequest.
common.restoreOverriddenRequests()
// We restore ClientRequest as it messes with recording of modules that also override ClientRequest (e.g. xhr2)
restoreOverriddenClientRequest()
}

// We override the requests so that we can save information on them before executing.
common.overrideRequests(function (proto, overriddenRequest, rawArgs) {
Expand Down
15 changes: 0 additions & 15 deletions tests/test_common.js
Expand Up @@ -287,21 +287,6 @@ describe('`matchStringOrRegexp()`', () => {
})
})

describe('`overrideRequests()`', () => {
afterEach(() => {
common.restoreOverriddenRequests()
})

it('should throw if called a second time', () => {
nock.restore()
common.overrideRequests()
// Second call throws.
expect(() => common.overrideRequests()).to.throw(
"Module's request already overridden for http protocol.",
)
})
})

it('`restoreOverriddenRequests()` can be called more than once', () => {
common.restoreOverriddenRequests()
common.restoreOverriddenRequests()
Expand Down

0 comments on commit 70caa2e

Please sign in to comment.