diff --git a/docs/adapters/node-http.md b/docs/adapters/node-http.md index 082fbf6b..02821a33 100644 --- a/docs/adapters/node-http.md +++ b/docs/adapters/node-http.md @@ -1,6 +1,6 @@ # Node HTTP Adapter -The node-http adapter provides a low level nodejs http request adapter that patches the [http](https://nodejs.org/api/http.html) and [https](https://nodejs.org/api/https.html) modules in nodejs for seamless recording and replaying of requests. +The node-http adapter provides a low level nodejs http request adapter that uses [nock](https://github.com/nock/nock) to patch the [http](https://nodejs.org/api/http.html) and [https](https://nodejs.org/api/https.html) modules in nodejs for seamless recording and replaying of requests. ## Installation @@ -42,25 +42,3 @@ polly.connectTo('node-http'); // Disconnect using the `disconnectFrom` API polly.disconnectFrom('node-http'); ``` - -## Options - -### transports - -_Type_: `Array` -_Default_: `['http', 'https']` - -The node transport modules to patch. By default, both the [http](https://nodejs.org/api/http.html) and [https](https://nodejs.org/api/https.html) modules are patched. In Node 8 and -below, the https module patching is skipped as it uses the http methods under the hood. - -**Example** - -```js -polly.configure({ - adapterOptions: { - 'node-http': { - transports: ['http'] - } - } -}); -``` diff --git a/docs/server/api.md b/docs/server/api.md index b8a2327a..92cb8f0f 100644 --- a/docs/server/api.md +++ b/docs/server/api.md @@ -2,7 +2,7 @@ ## HTTP Methods -The `get`, `put`, `post`, `patch`, `delete`, `head`, and `options` HTTP methods +The `GET`, `PUT`, `POST`, `PATCH`, `DELETE`, `MERGE`, `HEAD`, and `OPTIONS` HTTP methods have a corresponding method on the server instance. ```js @@ -11,6 +11,7 @@ server.put('/ping'); server.post('/ping'); server.patch('/ping'); server.delete('/ping'); +server.merge('/ping'); server.head('/ping'); server.options('/ping'); ``` diff --git a/packages/@pollyjs/adapter-node-http/README.md b/packages/@pollyjs/adapter-node-http/README.md index 273a7542..51656cf9 100644 --- a/packages/@pollyjs/adapter-node-http/README.md +++ b/packages/@pollyjs/adapter-node-http/README.md @@ -7,7 +7,7 @@ [![npm version](https://badge.fury.io/js/%40pollyjs%2Fadapter-node-http.svg)](https://badge.fury.io/js/%40pollyjs%2Fadapter-node-http) [![license](https://img.shields.io/github/license/Netflix/pollyjs.svg)](http://www.apache.org/licenses/LICENSE-2.0) -The `@pollyjs/adapter-node-http` package provides a low level nodejs http request adapter that patches the [http](https://nodejs.org/api/http.html) and [https](https://nodejs.org/api/https.html) modules in nodejs for seamless recording and replaying of requests. +The `@pollyjs/adapter-node-http` package provides a low level nodejs http request adapter that uses [nock](https://github.com/nock/nock) to patch the [http](https://nodejs.org/api/http.html) and [https](https://nodejs.org/api/https.html) modules in nodejs for seamless recording and replaying of requests. ## Installation diff --git a/packages/@pollyjs/adapter-node-http/package.json b/packages/@pollyjs/adapter-node-http/package.json index 01acb6e7..f2be0fac 100644 --- a/packages/@pollyjs/adapter-node-http/package.json +++ b/packages/@pollyjs/adapter-node-http/package.json @@ -48,6 +48,7 @@ "@pollyjs/adapter": "^1.4.1", "@pollyjs/utils": "^1.4.1", "lodash-es": "^4.17.11", + "nock": "^10.0.6", "semver": "^5.6.0" }, "devDependencies": { diff --git a/packages/@pollyjs/adapter-node-http/rollup.config.js b/packages/@pollyjs/adapter-node-http/rollup.config.js index 30178674..ac232f98 100644 --- a/packages/@pollyjs/adapter-node-http/rollup.config.js +++ b/packages/@pollyjs/adapter-node-http/rollup.config.js @@ -1,5 +1,5 @@ import createNodeConfig from '../../../build-scripts/rollup.node.config'; export default createNodeConfig({ - external: ['http', 'https', 'url'] + external: ['http', 'https', 'url', 'stream'] }); diff --git a/packages/@pollyjs/adapter-node-http/rollup.config.test.js b/packages/@pollyjs/adapter-node-http/rollup.config.test.js index 5bf27d2b..2585f29d 100644 --- a/packages/@pollyjs/adapter-node-http/rollup.config.test.js +++ b/packages/@pollyjs/adapter-node-http/rollup.config.test.js @@ -1,5 +1,5 @@ import createNodeTestConfig from '../../../build-scripts/rollup.node.test.config'; export default createNodeTestConfig({ - external: ['http', 'https', 'url', 'crypto'] + external: ['http', 'https', 'url', 'stream', 'crypto'] }); diff --git a/packages/@pollyjs/adapter-node-http/src/-private/http-wrapper.js b/packages/@pollyjs/adapter-node-http/src/-private/http-wrapper.js deleted file mode 100644 index 3e09e754..00000000 --- a/packages/@pollyjs/adapter-node-http/src/-private/http-wrapper.js +++ /dev/null @@ -1,38 +0,0 @@ -import http from 'http'; -import https from 'https'; - -import semver from 'semver'; - -import TransportWrapper from './transport-wrapper'; - -export default class HttpWrapper { - constructor({ adapter, options }) { - this.transports = []; - - if (options.transports.includes('http')) { - this.transports.push( - new TransportWrapper(http, { name: 'http', adapter }) - ); - } - - if ( - options.transports.includes('https') && - // Node 8 and below uses http.request under the hood for https.request - // so we should skip wrapping it even if enabled. - // https://github.com/nodejs/node/blob/v8.14.0/lib/https.js#L245 - semver.gte(process.version, '9.0.0') - ) { - this.transports.push( - new TransportWrapper(https, { name: 'https', adapter }) - ); - } - } - - patch() { - this.transports.forEach(transport => transport.patch()); - } - - restore() { - this.transports.forEach(transport => transport.restore()); - } -} diff --git a/packages/@pollyjs/adapter-node-http/src/-private/transport-wrapper.js b/packages/@pollyjs/adapter-node-http/src/-private/transport-wrapper.js deleted file mode 100644 index e7df5e19..00000000 --- a/packages/@pollyjs/adapter-node-http/src/-private/transport-wrapper.js +++ /dev/null @@ -1,304 +0,0 @@ -import http from 'http'; -import NodeUrl from 'url'; - -import isObjectLike from 'lodash-es/isObjectLike'; -import { URL } from '@pollyjs/utils'; - -import isBinaryBuffer from '../utils/is-binary-buffer'; -import isContentEncoded from '../utils/is-content-encoded'; -import mergeChunks from '../utils/merge-chunks'; - -const nativeRequestMapping = new WeakMap(); - -const { keys } = Object; - -export default class TransportWrapper { - constructor(transport, { name, adapter }) { - this.name = name; - this.adapter = adapter; - this.transport = transport; - } - - isPatched() { - return nativeRequestMapping.has(this.transport); - } - - patch() { - this.adapter.assert( - `The ${ - this.name - } transport has already been patched, please stop any running Polly instances`, - !this.isPatched() - ); - - const { transport } = this; - const { request, get } = transport; - - // Save the native methods so we can restore them later on - nativeRequestMapping.set(transport, { request, get }); - - transport.request = this.createRequestWrapper(); - // In Node 10+, http.get no longer references http.request by the export - // so we need to make sure we wrap it as well. - // https://github.com/nodejs/node/blob/v10.0.0/lib/https.js#L275 - transport.get = this.createGetWrapper(); - } - - restore() { - this.adapter.assert( - `Cannot restore unpatched transport ${this.name}`, - this.isPatched() - ); - - const { transport } = this; - const { request, get } = nativeRequestMapping.get(transport); - - transport.request = request; - transport.get = get; - - nativeRequestMapping.delete(transport); - } - - getBodyFromChunks(chunks, headers) { - const { adapter } = this; - - // If content-encoding is set in the header then the body/content - // should not be concatenated. Instead, the chunks should - // be preserved as-is so that each chunk can be mocked individually - if (isContentEncoded(headers)) { - const hexChunks = chunks.map(chunk => { - if (!Buffer.isBuffer(chunk)) { - adapter.assert( - 'content-encoded responses must all be binary buffers', - typeof chunk === 'string' - ); - chunk = Buffer.from(chunk); - } - - return chunk.toString('hex'); - }); - - return JSON.stringify(hexChunks); - } - - const buffer = mergeChunks(chunks); - - // The merged buffer can be one of two things: - // 1. A binary buffer which then has to be recorded as a hex string. - // 2. A string buffer. - return buffer.toString(isBinaryBuffer(buffer) ? 'hex' : 'utf8'); - } - - getChunksFromBody(body, headers) { - if (!body) { - return []; - } - - if (Buffer.isBuffer(body)) { - return [body]; - } - - // If content-encoding is set in the header then the body/content - // is as an array of hex strings - if (isContentEncoded(headers)) { - const hexChunks = JSON.parse(body); - - return hexChunks.map(chunk => Buffer.from(chunk, 'hex')); - } - - const buffer = Buffer.from(body); - - // The body can be one of two things: - // 1. A hex string which then means its binary data. - // 2. A utf8 string which means a regular string. - return [Buffer.from(buffer, isBinaryBuffer(buffer) ? 'hex' : 'utf8')]; - } - - async passthrough(pollyRequest) { - const { transport } = this; - const [, , args] = pollyRequest.requestArguments; - const { method, headers, body: chunks } = pollyRequest; - const { request: nativeRequest } = nativeRequestMapping.get(transport); - let [url, options] = args; - - /** - * args could be (url, options, callback) or (options, callback) depending - * on nodejs version. If the `url` arguments is not a string or URL - * instance, then use (options, callback). - */ - if (isObjectLike(url) && !url.searchParams) { - options = url; - url = undefined; - } - - const request = nativeRequest.call(transport, { - ...options, - method, - headers: { ...headers }, - ...NodeUrl.parse(pollyRequest.url) - }); - - const requestPromise = new Promise((resolve, reject) => { - request.once('response', response => resolve(response)); - request.once('error', reject); - }); - - // Write the request body - chunks.forEach(chunk => request.write(chunk)); - - request.end(); - const response = await requestPromise; - - const responseBody = await new Promise((resolve, reject) => { - const chunks = []; - - response.on('data', chunk => chunks.push(chunk)); - response.once('end', () => - resolve(this.getBodyFromChunks(chunks, response.headers)) - ); - response.once('error', reject); - }); - - return { - headers: response.headers, - statusCode: response.statusCode, - body: responseBody - }; - } - - async respond(pollyRequest) { - const { response: pollyResponse } = pollyRequest; - const [, req] = pollyRequest.requestArguments; - const fakeSocket = { readable: false }; - const response = new http.IncomingMessage(fakeSocket); - - response.statusCode = pollyResponse.statusCode; - response.headers = { ...pollyResponse.headers }; - response.rawHeaders = keys(response.headers).forEach(key => - response.rawHeaders.push(key, response.headers[key]) - ); - - await new Promise(resolve => process.nextTick(resolve)); - - req.emit('response', response); - - const chunks = this.getChunksFromBody( - pollyResponse.body, - pollyResponse.headers - ); - - setImmediate(function emitChunk() { - const chunk = chunks.shift(); - - if (chunk) { - response.push(chunk); - setImmediate(emitChunk); - } else { - response.push(null); - } - }); - - req.emit('prefinish'); - req.emit('finish'); - req.emit('end'); - } - - createRequestWrapper() { - const wrapper = this; - const { adapter, transport } = wrapper; - const { request: nativeRequest } = nativeRequestMapping.get(transport); - - return function request(...args) { - const req = nativeRequest.call(transport, ...args); - const nativeWrite = req.write; - const chunks = []; - let ended = false; - - // Pause the opened socket so it doesn't read any of the incoming data - req.once('socket', socket => socket.pause()); - - // Override req.write so we can save all the request body chunks - req.write = (chunk, encoding, callback) => { - if (!req.aborted) { - if (chunk) { - chunks.push( - Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding) - ); - } - } - - return nativeWrite.call(req, chunk, encoding, callback); - }; - - // Override req.end since this actual request is just a shell that never gets sent out. - // When we need to get actual data, a new request is made and a response - // is faked to this req. - req.end = (chunk, encoding, callback) => { - if (req.aborted || ended) { - return; - } - - ended = true; - - if (typeof chunk === 'function') { - callback = chunk; - chunk = undefined; - } else if (typeof encoding === 'function') { - callback = encoding; - encoding = undefined; - } - - if (chunk) { - req.write(chunk, encoding); - } - - // No need to carry callback around. This is what happens in original `end`. - if (typeof callback === 'function') { - req.once('finish', callback); - } - - const headers = - typeof req.getHeaders === 'function' - ? req.getHeaders() - : req.headers || req._headers || {}; - const host = headers.host; - const [hostname, port = '80'] = host.split(':'); - const { method, path } = req; - - const parsedUrl = new URL(''); - - parsedUrl.set('protocol', req.agent.protocol); - parsedUrl.set('pathname', path); - parsedUrl.set('hostname', hostname); - parsedUrl.set('port', port !== '80' ? port : ''); - - adapter - .handleRequest({ - method, - headers, - url: parsedUrl.href, - body: chunks, - requestArguments: [wrapper, req, args] - }) - .catch(e => { - // This allows the consumer to handle the error gracefully - req.emit('error', e); - }); - }; - - return req; - }; - } - - createGetWrapper() { - const { transport } = this; - - return function get(...args) { - const req = transport.request(...args); - - req.end(); - - return req; - }; - } -} diff --git a/packages/@pollyjs/adapter-node-http/src/index.js b/packages/@pollyjs/adapter-node-http/src/index.js index 2ce0052a..98181df9 100644 --- a/packages/@pollyjs/adapter-node-http/src/index.js +++ b/packages/@pollyjs/adapter-node-http/src/index.js @@ -1,49 +1,284 @@ +import http from 'http'; +import https from 'https'; +import URL from 'url'; +import { Readable } from 'stream'; + +import nock from 'nock'; +import semver from 'semver'; import Adapter from '@pollyjs/adapter'; +import { HTTP_METHODS } from '@pollyjs/utils'; + +import parseRequestArguments from './utils/parse-request-arguments'; +import getUrlFromOptions from './utils/get-url-from-options'; +import isBinaryBuffer from './utils/is-binary-buffer'; +import isContentEncoded from './utils/is-content-encoded'; +import mergeChunks from './utils/merge-chunks'; + +const IS_STUBBED = Symbol(); +const REQUEST_ARGUMENTS = new WeakMap(); -import HttpWrapper from './-private/http-wrapper'; +// nock begins to intercept network requests on import which is not the +// behavior we want, so restore the original behavior right away. +nock.restore(); export default class HttpAdapter extends Adapter { static get name() { return 'node-http'; } - get defaultOptions() { - return { - transports: ['http', 'https'] - }; - } - onConnect() { - const { transports } = this.options; - this.assert( - 'Invalid transports provided. At least one supported transport must be specified', - transports.includes('http') || transports.includes('https') + 'Running concurrent node-http adapters is unsupported, stop any running Polly instances.', + !http.ClientRequest[IS_STUBBED] + ); + this.assert( + 'Running nock concurrently with the node-http adapter is unsupported. Run nock.restore() before connecting to this adapter.', + !nock.isActive() ); - this.httpWrapper = new HttpWrapper({ - adapter: this, - options: this.options - }); - this.httpWrapper.patch(); + this.NativeClientRequest = http.ClientRequest; + this.setupNock(); + + // Patch methods overridden by nock to add some missing functionality + this.patchOverriddenMethods(); } onDisconnect() { - if (this.httpWrapper) { - this.httpWrapper.restore(); - delete this.httpWrapper; - } + nock.cleanAll(); + nock.restore(); + this.NativeClientRequest = null; + } + + setupNock() { + const adapter = this; + + // Make sure there aren't any other interceptors defined + nock.cleanAll(); + + // Create our interceptor that will match all hosts + const interceptor = nock(/.*/).persist(); + + HTTP_METHODS.forEach(m => { + // Add an intercept for each supported HTTP method that will match all paths + interceptor.intercept(/.*/, m).reply(function(_, body, respond) { + const { req, method } = this; + const { headers } = req; + const parsedArguments = parseRequestArguments( + ...REQUEST_ARGUMENTS.get(req) + ); + const url = getUrlFromOptions(parsedArguments.options); + + // body will always be a string unless the content-type is application/json + // in which nock will then parse into an object. We have our own way of + // dealing with json content to convert it back to a string. + if (body && typeof body !== 'string') { + body = JSON.stringify(body); + } + + adapter + .handleRequest({ + url, + method, + headers, + body, + requestArguments: { req, body, respond, parsedArguments } + }) + .catch(e => { + // This allows the consumer to handle the error gracefully + req.emit('error', e); + }); + }); + }); + + // Activate nock so it can start to intercept all outgoing requests + nock.activate(); + } + + patchOverriddenMethods() { + const modules = { http, https }; + const { ClientRequest } = http; + + // Patch the already overridden ClientRequest class so we can get + // access to the original arguments and use them when creating the + // passthrough request. + http.ClientRequest = function _ClientRequest() { + const req = new ClientRequest(...arguments); + + REQUEST_ARGUMENTS.set(req, [...arguments]); + + return req; + }; + + // Add an IS_STUBBED boolean so we can check on onConnect if we've already + // patched the necessary methods. + http.ClientRequest[IS_STUBBED] = true; + + // Patch http.request, http.get, https.request, and https.get + // to support new Node.js 10.9 signature `http.request(url[, options][, callback])` + // (https://github.com/nock/nock/issues/1227). + // + // This patch is also needed to set some default values which nock doesn't + // properly set. + Object.keys(modules).forEach(moduleName => { + const module = modules[moduleName]; + const { request, get, globalAgent } = module; + const parseArgs = function() { + const args = parseRequestArguments(...arguments); + + if (moduleName === 'https') { + args.options = { + ...{ port: 443, protocol: 'https:', _defaultAgent: globalAgent }, + ...args.options + }; + } else { + args.options = { + ...{ port: 80, protocol: 'http:' }, + ...args.options + }; + } + + return args; + }; + + module.request = function _request() { + const { options, callback } = parseArgs(...arguments); + + return request(options, callback); + }; + + if (semver.satisfies(process.version, '>=8')) { + module.get = function _get() { + const { options, callback } = parseArgs(...arguments); + + return get(options, callback); + }; + } + }); } async passthroughRequest(pollyRequest) { - const [transportWrapper] = pollyRequest.requestArguments; + const { parsedArguments } = pollyRequest.requestArguments; + const { method, headers, body } = pollyRequest; + const { options } = parsedArguments; + + const request = new this.NativeClientRequest({ + ...options, + method, + headers: { ...headers }, + ...URL.parse(pollyRequest.url) + }); + + const chunks = this.getChunksFromBody(body, headers); + + const responsePromise = new Promise((resolve, reject) => { + request.once('response', resolve); + request.once('error', reject); + request.once('timeout', reject); + }); + + // Write the request body + chunks.forEach(chunk => request.write(chunk)); + request.end(); + + const response = await responsePromise; + const responseBody = await new Promise((resolve, reject) => { + const chunks = []; - return transportWrapper.passthrough(pollyRequest); + response.on('data', chunk => chunks.push(chunk)); + response.once('end', () => + resolve(this.getBodyFromChunks(chunks, response.headers)) + ); + response.once('error', reject); + }); + + return { + headers: response.headers, + statusCode: response.statusCode, + body: responseBody + }; } async respondToRequest(pollyRequest) { - const [transportWrapper] = pollyRequest.requestArguments; + const { statusCode, body, headers } = pollyRequest.response; + const { req, respond } = pollyRequest.requestArguments; + const chunks = this.getChunksFromBody(body, headers); + const stream = new Readable(); + + // Expose the response data as a stream of chunks since + // it could contain encoded data which is needed + // to be pushed to the response chunk by chunk. + chunks.forEach(chunk => stream.push(chunk)); + stream.push(null); + + // Create a promise that will resolve once the request + // has been completed (including errored or aborted). This is needed so + // that the deferred promise used by `polly.flush()` doesn't resolve before + // the response was actually received. + const requestFinishedPromise = new Promise(resolve => { + if (req.aborted) { + resolve(); + } else { + req.once('response', resolve); + req.once('abort', resolve); + req.once('error', resolve); + } + }); + + respond(null, [statusCode, stream, headers]); + + await requestFinishedPromise; + } + + getBodyFromChunks(chunks, headers) { + // If content-encoding is set in the header then the body/content + // should not be concatenated. Instead, the chunks should + // be preserved as-is so that each chunk can be mocked individually + if (isContentEncoded(headers)) { + const hexChunks = chunks.map(chunk => { + if (!Buffer.isBuffer(chunk)) { + this.assert( + 'content-encoded responses must all be binary buffers', + typeof chunk === 'string' + ); + chunk = Buffer.from(chunk); + } + + return chunk.toString('hex'); + }); + + return JSON.stringify(hexChunks); + } + + const buffer = mergeChunks(chunks); + + // The merged buffer can be one of two things: + // 1. A binary buffer which then has to be recorded as a hex string. + // 2. A string buffer. + return buffer.toString(isBinaryBuffer(buffer) ? 'hex' : 'utf8'); + } + + getChunksFromBody(body, headers) { + if (!body) { + return []; + } + + if (Buffer.isBuffer(body)) { + return [body]; + } + + // If content-encoding is set in the header then the body/content + // is as an array of hex strings + if (isContentEncoded(headers)) { + const hexChunks = JSON.parse(body); + + return hexChunks.map(chunk => Buffer.from(chunk, 'hex')); + } + + const buffer = Buffer.from(body); - return transportWrapper.respond(pollyRequest); + // The body can be one of two things: + // 1. A hex string which then means its binary data. + // 2. A utf8 string which means a regular string. + return [Buffer.from(buffer, isBinaryBuffer(buffer) ? 'hex' : 'utf8')]; } } diff --git a/packages/@pollyjs/adapter-node-http/src/utils/get-url-from-options.js b/packages/@pollyjs/adapter-node-http/src/utils/get-url-from-options.js new file mode 100644 index 00000000..da8567e4 --- /dev/null +++ b/packages/@pollyjs/adapter-node-http/src/utils/get-url-from-options.js @@ -0,0 +1,34 @@ +import { URL } from '@pollyjs/utils'; + +/** + * Generate an absolute url from options passed into `new http.ClientRequest`. + * + * @export + * @param {Object} [options] + * @returns {string} + */ +export default function getUrlFromOptions(options = {}) { + if (options.href) { + return options.href; + } + + const protocol = options.protocol || `${options.proto}:` || 'http:'; + const host = options.hostname || options.host || 'localhost'; + const { path, port } = options; + const url = new URL(); + + url.set('protocol', protocol); + url.set('host', host); + url.set('pathname', path); + + if ( + port && + !host.includes(':') && + (port !== 80 || protocol !== 'http:') && + (port !== 443 || protocol !== 'https:') + ) { + url.set('port', port); + } + + return url.href; +} diff --git a/packages/@pollyjs/adapter-node-http/src/utils/is-binary-buffer.js b/packages/@pollyjs/adapter-node-http/src/utils/is-binary-buffer.js index 875fd891..13bfc2fd 100644 --- a/packages/@pollyjs/adapter-node-http/src/utils/is-binary-buffer.js +++ b/packages/@pollyjs/adapter-node-http/src/utils/is-binary-buffer.js @@ -1,3 +1,24 @@ +/** + * Determine if the given buffer is binary. + * + * @export + * @param {Buffer} [buffer] + * @returns {boolean} + */ +export default function isBinaryBuffer(buffer) { + if (!Buffer.isBuffer(buffer)) { + return false; + } + + // Test if the buffer can be reconstructed verbatim from its utf8 encoding. + const utfEncodedBuffer = buffer.toString('utf8'); + const reconstructedBuffer = Buffer.from(utfEncodedBuffer, 'utf8'); + + // If the buffers are *not* equal then this is a "binary buffer" + // meaning that it cannot be faithfully represented in utf8. + return !compareBuffers(buffer, reconstructedBuffer); +} + function compareBuffers(lhs, rhs) { if (lhs.length !== rhs.length) { return false; @@ -11,17 +32,3 @@ function compareBuffers(lhs, rhs) { return true; } - -export default function isBinaryBuffer(buffer) { - if (!Buffer.isBuffer(buffer)) { - return false; - } - - // Test if the buffer can be reconstructed verbatim from its utf8 encoding. - const utfEncodedBuffer = buffer.toString('utf8'); - const reconstructedBuffer = Buffer.from(utfEncodedBuffer, 'utf8'); - - // If the buffers are *not* equal then this is a "binary buffer" - // meaning that it cannot be faitfully represented in utf8. - return !compareBuffers(buffer, reconstructedBuffer); -} diff --git a/packages/@pollyjs/adapter-node-http/src/utils/is-content-encoded.js b/packages/@pollyjs/adapter-node-http/src/utils/is-content-encoded.js index 47141b73..adff7ba4 100644 --- a/packages/@pollyjs/adapter-node-http/src/utils/is-content-encoded.js +++ b/packages/@pollyjs/adapter-node-http/src/utils/is-content-encoded.js @@ -1,5 +1,12 @@ import isObjectLike from 'lodash-es/isObjectLike'; +/** + * Determine if a request's content is encoded by the headers it has. + * + * @export + * @param {Object} [headers] + * @returns {boolean} + */ export default function isContentEncoded(headers) { const contentEncoding = isObjectLike(headers) ? headers['content-encoding'] diff --git a/packages/@pollyjs/adapter-node-http/src/utils/merge-chunks.js b/packages/@pollyjs/adapter-node-http/src/utils/merge-chunks.js index c1487b8a..5e54154c 100644 --- a/packages/@pollyjs/adapter-node-http/src/utils/merge-chunks.js +++ b/packages/@pollyjs/adapter-node-http/src/utils/merge-chunks.js @@ -1,3 +1,11 @@ +/** + * Merge an array of strings into a single string or concat an array + * of buffers into a single buffer. + * + * @export + * @param {string[] | Buffer[]} [chunks] + * @returns {string | Buffer} + */ export default function mergeChunks(chunks) { if (!chunks || chunks.length === 0) { return Buffer.alloc(0); diff --git a/packages/@pollyjs/adapter-node-http/src/utils/parse-request-arguments.js b/packages/@pollyjs/adapter-node-http/src/utils/parse-request-arguments.js new file mode 100644 index 00000000..548e6564 --- /dev/null +++ b/packages/@pollyjs/adapter-node-http/src/utils/parse-request-arguments.js @@ -0,0 +1,33 @@ +import NodeUrl from 'url'; + +const { URL, parse } = NodeUrl; + +/** + * Parse possible arguments passed into `new http.ClientRequest`. + * + * @export + * @param {string | URL} [url] + * @param {Object} [options] + * @param {Function} [callback] + * @returns {Object} + */ +export default function parseRequestArguments(url, options, callback) { + if (typeof url === 'string') { + url = parse(url); + } else if (URL && url instanceof URL) { + url = parse(`${url}`); + } else { + callback = options; + options = url; + url = null; + } + + if (typeof options === 'function') { + callback = options; + options = null; + } + + options = { ...(url || {}), ...(options || {}) }; + + return { options, callback }; +} diff --git a/packages/@pollyjs/adapter-node-http/tests/integration/adapter-test.js b/packages/@pollyjs/adapter-node-http/tests/integration/adapter-test.js index aa036f80..f3e2a52b 100644 --- a/packages/@pollyjs/adapter-node-http/tests/integration/adapter-test.js +++ b/packages/@pollyjs/adapter-node-http/tests/integration/adapter-test.js @@ -1,62 +1,68 @@ import http from 'http'; import https from 'https'; -import semver from 'semver'; import setupFetchRecord from '@pollyjs-tests/helpers/setup-fetch-record'; import adapterTests from '@pollyjs-tests/integration/adapter-tests'; -import { setupMocha as setupPolly } from '@pollyjs/core'; +import { Polly, setupMocha as setupPolly } from '@pollyjs/core'; +import NodeHTTPAdapter from '../../src'; import nativeRequest from '../utils/native-request'; import setupPollyConfig from '../utils/setup-polly-config'; import getResponseFromRequest from '../utils/get-response-from-request'; import calculateHashFromStream from '../utils/calculate-hash-from-stream'; -const NativeMethods = new Map([ - [http, { get: http.get, request: http.request }], - [https, { get: https.get, request: https.request }] -]); +describe('Integration | Node Http Adapter', function() { + describe('Concurrency', function() { + it('should prevent concurrent Node HTTP adapter instances', async function() { + const one = new Polly('one'); + const two = new Polly('two'); -function testTransportPatching(transport) { - it('should patch and unpatch', function() { - const { get, request } = NativeMethods.get(transport); + one.connectTo(NodeHTTPAdapter); - expect(transport.get).to.not.equal(get); - expect(transport.request).to.not.equal(request); + expect(function() { + two.connectTo(NodeHTTPAdapter); + }).to.throw(/Running concurrent node-http adapters is unsupported/); - this.polly.disconnectFrom('node-http'); + await one.stop(); + await two.stop(); + }); - expect(transport.get).to.equal(get); - expect(transport.request).to.equal(request); - }); -} + it('should prevent running nock concurrently with the node-http adapter', async function() { + const polly = new Polly('nock'); + const nock = require('nock'); -function testBinaryDownload(transport) { - const { protocol } = transport.globalAgent; - const url = `${protocol}//via.placeholder.com/150/92c952`; + nock.activate(); - it('should be able to download binary content', async function() { - const { server } = this.polly; + expect(function() { + polly.connectTo(NodeHTTPAdapter); + }).to.throw( + /Running nock concurrently with the node-http adapter is unsupported/ + ); - server.get(url).passthrough(true); + nock.restore(); + await polly.stop(); + }); + }); - const nativeResponseStream = await getResponseFromRequest( - transport.request(url) - ); + describe('http', function() { + setupPolly.beforeEach(setupPollyConfig); - server.get(url).passthrough(false); + setupFetchRecord({ + host: 'http://localhost:4000', + fetch: nativeRequest.bind(undefined, http) + }); - const recordedResponseStream = await getResponseFromRequest( - transport.request(url) - ); + setupPolly.afterEach(); - const [nativeHash, recordedHash] = await Promise.all([ - calculateHashFromStream(nativeResponseStream), - calculateHashFromStream(recordedResponseStream) - ]); + adapterTests(); + commonTests(http); + }); - expect(nativeHash).to.equal(recordedHash); + describe('https', function() { + setupPolly(setupPollyConfig); + commonTests(https); }); -} +}); function commonTests(transport) { const { protocol } = transport.globalAgent; @@ -79,33 +85,28 @@ function commonTests(transport) { expect(requests[0].id).to.equal(requests[1].id); expect(requests[0].identifiers.body).to.equal(body.toString('hex')); }); -} -describe('Integration | Node Http Adapter', function() { - describe('http', function() { - setupPolly.beforeEach(setupPollyConfig); + it('should be able to download binary content', async function() { + const url = `${protocol}//via.placeholder.com/150/92c952`; + const { server } = this.polly; - setupFetchRecord({ - host: 'http://localhost:4000', - fetch: nativeRequest.bind(undefined, http) - }); + server.get(url).passthrough(true); - setupPolly.afterEach(); + const nativeResponseStream = await getResponseFromRequest( + transport.request(url) + ); - adapterTests(); - testTransportPatching(http); - testBinaryDownload(http); - commonTests(http); - }); + server.get(url).passthrough(false); - describe('https', function() { - setupPolly(setupPollyConfig); + const recordedResponseStream = await getResponseFromRequest( + transport.request(url) + ); - if (semver.gte(process.version, '9.0.0')) { - testTransportPatching(http); - } + const [nativeHash, recordedHash] = await Promise.all([ + calculateHashFromStream(nativeResponseStream), + calculateHashFromStream(recordedResponseStream) + ]); - testBinaryDownload(https); - commonTests(https); + expect(nativeHash).to.equal(recordedHash); }); -}); +} diff --git a/packages/@pollyjs/core/src/server/index.js b/packages/@pollyjs/core/src/server/index.js index 161e3929..47926f1c 100644 --- a/packages/@pollyjs/core/src/server/index.js +++ b/packages/@pollyjs/core/src/server/index.js @@ -1,6 +1,6 @@ import RouteRecognizer from 'route-recognizer'; import castArray from 'lodash-es/castArray'; -import { URL, assert, timeout, buildUrl } from '@pollyjs/utils'; +import { HTTP_METHODS, URL, assert, timeout, buildUrl } from '@pollyjs/utils'; import Route from './route'; import Handler from './handler'; @@ -18,8 +18,6 @@ const CHARS = { COLON: ':' }; -const METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']; - const { keys } = Object; function parseUrl(url) { @@ -84,6 +82,10 @@ export default class Server { return this._register('PATCH', ...arguments); } + merge() { + return this._register('MERGE', ...arguments); + } + head() { return this._register('HEAD', ...arguments); } @@ -200,7 +202,7 @@ export default class Server { _registryForHost(host) { if (!this[REGISTRY][host]) { - this[REGISTRY][host] = METHODS.reduce((acc, method) => { + this[REGISTRY][host] = HTTP_METHODS.reduce((acc, method) => { acc[method] = new RouteRecognizer(); acc[method][HANDLERS] = new Map(); diff --git a/packages/@pollyjs/core/tests/unit/server/server-test.js b/packages/@pollyjs/core/tests/unit/server/server-test.js index 4b01075d..a23fc6b3 100644 --- a/packages/@pollyjs/core/tests/unit/server/server-test.js +++ b/packages/@pollyjs/core/tests/unit/server/server-test.js @@ -1,6 +1,6 @@ -import Server from '../../../src/server'; +import { HTTP_METHODS } from '@pollyjs/utils'; -const METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']; +import Server from '../../../src/server'; let server; @@ -20,14 +20,14 @@ describe('Unit | Server', function() { }); it('should handle all HTTP methods', function() { - METHODS.forEach(method => { + HTTP_METHODS.forEach(method => { server[method.toLowerCase()]('/foo').intercept(() => 200); expect(request(method, '/foo')).to.equal(200); }); }); it('should handle multiple routes on all HTTP methods', function() { - METHODS.forEach(method => { + HTTP_METHODS.forEach(method => { server[method.toLowerCase()]([ `/${method}`, `/${method}/*path` diff --git a/packages/@pollyjs/utils/src/constants/http-methods.js b/packages/@pollyjs/utils/src/constants/http-methods.js new file mode 100644 index 00000000..2b998b40 --- /dev/null +++ b/packages/@pollyjs/utils/src/constants/http-methods.js @@ -0,0 +1,10 @@ +export default [ + 'GET', + 'PUT', + 'POST', + 'DELETE', + 'PATCH', + 'MERGE', + 'HEAD', + 'OPTIONS' +]; diff --git a/packages/@pollyjs/utils/src/index.js b/packages/@pollyjs/utils/src/index.js index 670b5a78..6ba7e664 100644 --- a/packages/@pollyjs/utils/src/index.js +++ b/packages/@pollyjs/utils/src/index.js @@ -1,5 +1,6 @@ export { default as MODES } from './constants/modes'; export { default as ACTIONS } from './constants/actions'; +export { default as HTTP_METHODS } from './constants/http-methods'; export { default as HTTP_STATUS_CODES } from './constants/http-status-codes'; export { default as assert } from './utils/assert'; diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-be-able-to-abort-from-an-intercept_68559697/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-be-able-to-abort-from-an-intercept_68559697/recording.har index af95dbfe..0c92ac72 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-be-able-to-abort-from-an-intercept_68559697/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-be-able-to-abort-from-an-intercept_68559697/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "df96b74e6da6dcefa3f1eb6419797054", + "_id": "840f650e2cf2ed48bda437606e4e6a6f", "_order": 0, "cache": {}, "request": { @@ -47,9 +47,6 @@ "headersSize": 356, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-be-able-to-abort-from-an-intercept_68559697" }, @@ -67,7 +64,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -84,7 +81,7 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:00.746Z", + "startedDateTime": "2019-01-23T23:48:25.828Z", "time": 6, "timings": { "blocked": -1, diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-call-all-the-life-cycle-events_2199659288/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-call-all-the-life-cycle-events_2199659288/recording.har index fa799f30..43ba2a3a 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-call-all-the-life-cycle-events_2199659288/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-call-all-the-life-cycle-events_2199659288/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "a49db3094e55eb5c5633814929517208", + "_id": "0053563c13b96bdde5d2dd349b7656d6", "_order": 0, "cache": {}, "request": { @@ -47,9 +47,6 @@ "headersSize": 354, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-call-all-the-life-cycle-events_2199659288" }, @@ -67,7 +64,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -84,8 +81,8 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:00.771Z", - "time": 3, + "startedDateTime": "2019-01-23T23:48:25.852Z", + "time": 2, "timings": { "blocked": -1, "connect": -1, @@ -93,7 +90,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 3 + "wait": 2 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-handle-a-compressed-response_479521015/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-handle-a-compressed-response_479521015/recording.har index 1398e567..5a20af5b 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-handle-a-compressed-response_479521015/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-handle-a-compressed-response_479521015/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "c6b2fe3392457eed39ef7aabb99542eb", + "_id": "ff44ed3f1f9a17bd8d3aa651a8afe7f2", "_order": 0, "cache": {}, "request": { @@ -62,7 +62,8 @@ "postData": { "mimeType": [ "application/json" - ] + ], + "text": "{\"foo\":\"bar\"}" }, "queryString": [], "url": "http://localhost:4000/compress" @@ -90,7 +91,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 23:23:10 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -107,8 +108,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T23:23:10.205Z", - "time": 4, + "startedDateTime": "2019-01-23T23:48:25.861Z", + "time": 8, "timings": { "blocked": -1, "connect": -1, @@ -116,7 +117,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 4 + "wait": 8 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-properly-handle-204-status-code-response_1592697261/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-properly-handle-204-status-code-response_1592697261/recording.har index a6f67e9e..7b5d33fc 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-properly-handle-204-status-code-response_1592697261/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-properly-handle-204-status-code-response_1592697261/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "1537cbdd46d9296bafb2247830a711ba", + "_id": "864ec388c6911bc5c767545977ee5bcb", "_order": 0, "cache": {}, "request": { @@ -47,9 +47,6 @@ "headersSize": 207, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [ { "name": "status", @@ -84,7 +81,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -97,8 +94,8 @@ "status": 204, "statusText": "No Content" }, - "startedDateTime": "2018-12-03T19:39:00.678Z", - "time": 5, + "startedDateTime": "2019-01-23T23:48:25.788Z", + "time": 8, "timings": { "blocked": -1, "connect": -1, @@ -106,7 +103,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 5 + "wait": 8 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-respect-request-order_2914185093/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-respect-request-order_2914185093/recording.har index c219cb2b..92aa78d2 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-respect-request-order_2914185093/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter-node-fetch_3496513759/should-respect-request-order_2914185093/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "cb76b57af4ee16cbd3face75a4ace3c3", + "_id": "a96b8d8822cccbfe23cf5bf304dab762", "_order": 0, "cache": {}, "request": { @@ -47,9 +47,6 @@ "headersSize": 345, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-respect-request-order_2914185093" }, @@ -67,7 +64,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -84,8 +81,8 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:00.560Z", - "time": 26, + "startedDateTime": "2019-01-23T23:48:25.690Z", + "time": 27, "timings": { "blocked": -1, "connect": -1, @@ -93,11 +90,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 26 + "wait": 27 } }, { - "_id": "ad8721465b41e92d5c8d1951c0e0dd7e", + "_id": "1ad56d1b87a0ea954e274ab3579a1f88", "_order": 0, "cache": {}, "request": { @@ -151,7 +148,8 @@ "postData": { "mimeType": [ "application/json" - ] + ], + "text": "{\"foo\":\"bar\"}" }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-respect-request-order_2914185093" @@ -183,7 +181,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -196,8 +194,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:00.596Z", - "time": 42, + "startedDateTime": "2019-01-23T23:48:25.726Z", + "time": 26, "timings": { "blocked": -1, "connect": -1, @@ -205,11 +203,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 42 + "wait": 26 } }, { - "_id": "cb76b57af4ee16cbd3face75a4ace3c3", + "_id": "a96b8d8822cccbfe23cf5bf304dab762", "_order": 1, "cache": {}, "request": { @@ -248,9 +246,6 @@ "headersSize": 345, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-respect-request-order_2914185093" }, @@ -281,7 +276,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -294,7 +289,7 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:00.641Z", + "startedDateTime": "2019-01-23T23:48:25.754Z", "time": 3, "timings": { "blocked": -1, @@ -307,7 +302,7 @@ } }, { - "_id": "466058c77239905485edaa3827e533f7", + "_id": "e5b70d953b27950cec926d8d2fb42970", "_order": 0, "cache": {}, "request": { @@ -346,9 +341,6 @@ "headersSize": 348, "httpVersion": "HTTP/1.1", "method": "DELETE", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-respect-request-order_2914185093" }, @@ -366,7 +358,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -383,8 +375,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:00.648Z", - "time": 4, + "startedDateTime": "2019-01-23T23:48:25.761Z", + "time": 2, "timings": { "blocked": -1, "connect": -1, @@ -392,11 +384,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 4 + "wait": 2 } }, { - "_id": "cb76b57af4ee16cbd3face75a4ace3c3", + "_id": "a96b8d8822cccbfe23cf5bf304dab762", "_order": 2, "cache": {}, "request": { @@ -435,9 +427,6 @@ "headersSize": 345, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter-node-fetch_3496513759%2Fshould-respect-request-order_2914185093" }, @@ -455,7 +444,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:00 GMT" + "value": "Wed, 23 Jan 2019 23:48:25 GMT" }, { "name": "connection", @@ -472,7 +461,7 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:00.654Z", + "startedDateTime": "2019-01-23T23:48:25.765Z", "time": 2, "timings": { "blocked": -1, diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-abort-from-an-intercept_68559697/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-abort-from-an-intercept_68559697/recording.har index 223a4641..c6999bf5 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-abort-from-an-intercept_68559697/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-abort-from-an-intercept_68559697/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "38612e9bafa2b5764aa52563ffd80e4e", + "_id": "6420702b14e4369ca8c89dfd32b71012", "_order": 0, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 232, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-be-able-to-abort-from-an-intercept_68559697" }, @@ -43,7 +40,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -60,7 +57,7 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:01.161Z", + "startedDateTime": "2019-01-23T23:48:26.238Z", "time": 3, "timings": { "blocked": -1, diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-download-binary-content_2339860906/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-download-binary-content_2339860906/recording.har index 869efee3..28b2b9e2 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-download-binary-content_2339860906/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-be-able-to-download-binary-content_2339860906/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "12660658803cc1206a9c71c67bcad753", + "_id": "91ca74e50a51e73418fecde9eb157cd9", "_order": 1, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 81, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://via.placeholder.com/150/92c952" }, @@ -44,7 +41,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:05 GMT" + "value": "Wed, 23 Jan 2019 23:48:28 GMT" }, { "name": "content-type", @@ -56,7 +53,7 @@ }, { "name": "last-modified", - "value": "Mon, 05 Nov 2018 20:00:16 GMT" + "value": "Sun, 06 Jan 2019 22:00:11 GMT" }, { "name": "connection", @@ -64,11 +61,11 @@ }, { "name": "etag", - "value": "\"5be0a150-175\"" + "value": "\"5c327a6b-175\"" }, { "name": "expires", - "value": "Mon, 10 Dec 2018 19:39:05 GMT" + "value": "Wed, 30 Jan 2019 23:48:28 GMT" }, { "name": "cache-control", @@ -89,8 +86,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:01.533Z", - "time": 90, + "startedDateTime": "2019-01-23T23:48:28.683Z", + "time": 143, "timings": { "blocked": -1, "connect": -1, @@ -98,7 +95,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 90 + "wait": 143 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-call-all-the-life-cycle-events_2199659288/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-call-all-the-life-cycle-events_2199659288/recording.har index 2284e468..5570aed6 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-call-all-the-life-cycle-events_2199659288/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-call-all-the-life-cycle-events_2199659288/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "94e1064ebae51a6321c4d4283138c17d", + "_id": "85c3b140dc10be0b26bd4b43999fe62e", "_order": 0, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 230, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-call-all-the-life-cycle-events_2199659288" }, @@ -43,7 +40,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -60,8 +57,8 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:01.185Z", - "time": 3, + "startedDateTime": "2019-01-23T23:48:26.261Z", + "time": 4, "timings": { "blocked": -1, "connect": -1, @@ -69,7 +66,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 3 + "wait": 4 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-handle-a-compressed-response_479521015/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-handle-a-compressed-response_479521015/recording.har index a027ad93..d2531702 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-handle-a-compressed-response_479521015/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-handle-a-compressed-response_479521015/recording.har @@ -8,11 +8,11 @@ }, "entries": [ { - "_id": "87a70e84e93d44003f26f5ab2d943416", + "_id": "13f22e4bbbaf56b93ae5a0c3856bd872", "_order": 0, "cache": {}, "request": { - "bodySize": 0, + "bodySize": 13, "cookies": [], "headers": [ { @@ -28,7 +28,8 @@ "httpVersion": "HTTP/1.1", "method": "POST", "postData": { - "mimeType": "application/json" + "mimeType": "application/json", + "text": "{\"foo\":\"bar\"}" }, "queryString": [], "url": "http://localhost:4000/compress" @@ -52,7 +53,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 23:23:10 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -69,7 +70,7 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T23:23:10.566Z", + "startedDateTime": "2019-01-23T23:48:26.277Z", "time": 4, "timings": { "blocked": -1, diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-properly-handle-204-status-code-response_1592697261/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-properly-handle-204-status-code-response_1592697261/recording.har index 7418085f..323e61bf 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-properly-handle-204-status-code-response_1592697261/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-properly-handle-204-status-code-response_1592697261/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "53c45334b33cd8ef0bdc05beb242b0b9", + "_id": "d72c2b357e7cf0d4037121da2fe251b1", "_order": 0, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 76, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [ { "name": "status", @@ -60,7 +57,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -73,8 +70,8 @@ "status": 204, "statusText": "No Content" }, - "startedDateTime": "2018-12-03T19:39:01.115Z", - "time": 4, + "startedDateTime": "2019-01-23T23:48:26.197Z", + "time": 3, "timings": { "blocked": -1, "connect": -1, @@ -82,7 +79,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 4 + "wait": 3 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-respect-request-order_2914185093/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-respect-request-order_2914185093/recording.har index c9d76b4d..ce327a38 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-respect-request-order_2914185093/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/http_3378792613/should-respect-request-order_2914185093/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "958b3066bffed1d48d3bc018e6394015", + "_id": "a8d10622bf3fb7ae959ea2855832cd87", "_order": 0, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 221, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-respect-request-order_2914185093" }, @@ -43,7 +40,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -60,8 +57,8 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:01.081Z", - "time": 4, + "startedDateTime": "2019-01-23T23:48:26.142Z", + "time": 12, "timings": { "blocked": -1, "connect": -1, @@ -69,15 +66,15 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 4 + "wait": 12 } }, { - "_id": "c9c42b097ae28d941a3730bd31e4678e", + "_id": "952af59d45f801ede9d0db1126184111", "_order": 0, "cache": {}, "request": { - "bodySize": 0, + "bodySize": 13, "cookies": [], "headers": [ { @@ -93,7 +90,8 @@ "httpVersion": "HTTP/1.1", "method": "POST", "postData": { - "mimeType": "application/json" + "mimeType": "application/json", + "text": "{\"foo\":\"bar\"}" }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-respect-request-order_2914185093" @@ -125,7 +123,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -138,8 +136,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:01.088Z", - "time": 3, + "startedDateTime": "2019-01-23T23:48:26.156Z", + "time": 4, "timings": { "blocked": -1, "connect": -1, @@ -147,11 +145,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 3 + "wait": 4 } }, { - "_id": "958b3066bffed1d48d3bc018e6394015", + "_id": "a8d10622bf3fb7ae959ea2855832cd87", "_order": 1, "cache": {}, "request": { @@ -166,9 +164,6 @@ "headersSize": 221, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-respect-request-order_2914185093" }, @@ -199,7 +194,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -212,7 +207,7 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:01.093Z", + "startedDateTime": "2019-01-23T23:48:26.161Z", "time": 3, "timings": { "blocked": -1, @@ -225,7 +220,7 @@ } }, { - "_id": "2e3c6c5812ad2b86f9345b80821cda41", + "_id": "4755ec2f705d0e825068e0d5def438a0", "_order": 0, "cache": {}, "request": { @@ -240,9 +235,6 @@ "headersSize": 224, "httpVersion": "HTTP/1.1", "method": "DELETE", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-respect-request-order_2914185093" }, @@ -260,7 +252,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -277,8 +269,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:01.097Z", - "time": 3, + "startedDateTime": "2019-01-23T23:48:26.165Z", + "time": 2, "timings": { "blocked": -1, "connect": -1, @@ -286,11 +278,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 3 + "wait": 2 } }, { - "_id": "958b3066bffed1d48d3bc018e6394015", + "_id": "a8d10622bf3fb7ae959ea2855832cd87", "_order": 2, "cache": {}, "request": { @@ -305,9 +297,6 @@ "headersSize": 221, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "http://localhost:4000/api/db/-pollyjs_2160168770%2Fadapter-node-http_1501306138%2FIntegration-Node-Http-Adapter_1543864754%2Fhttp_3378792613%2Fshould-respect-request-order_2914185093" }, @@ -325,7 +314,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:01 GMT" + "value": "Wed, 23 Jan 2019 23:48:26 GMT" }, { "name": "connection", @@ -342,8 +331,8 @@ "status": 404, "statusText": "Not Found" }, - "startedDateTime": "2018-12-03T19:39:01.101Z", - "time": 5, + "startedDateTime": "2019-01-23T23:48:26.169Z", + "time": 2, "timings": { "blocked": -1, "connect": -1, @@ -351,7 +340,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 5 + "wait": 2 } } ], diff --git a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/https_3739134178/should-be-able-to-download-binary-content_2339860906/recording.har b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/https_3739134178/should-be-able-to-download-binary-content_2339860906/recording.har index 8e135b4c..c55b7e1d 100644 --- a/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/https_3739134178/should-be-able-to-download-binary-content_2339860906/recording.har +++ b/tests/recordings/-pollyjs_2160168770/adapter-node-http_1501306138/Integration-Node-Http-Adapter_1543864754/https_3739134178/should-be-able-to-download-binary-content_2339860906/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "280008c7d5a7f7fa4f2327ed889664e4", + "_id": "92a4dd37a009fe76ac7dacabd98dc612", "_order": 1, "cache": {}, "request": { @@ -23,9 +23,6 @@ "headersSize": 82, "httpVersion": "HTTP/1.1", "method": "GET", - "postData": { - "mimeType": "text/plain" - }, "queryString": [], "url": "https://via.placeholder.com/150/92c952" }, @@ -44,7 +41,7 @@ }, { "name": "date", - "value": "Mon, 03 Dec 2018 19:39:06 GMT" + "value": "Thu, 24 Jan 2019 19:00:57 GMT" }, { "name": "content-type", @@ -56,7 +53,7 @@ }, { "name": "last-modified", - "value": "Mon, 05 Nov 2018 20:00:16 GMT" + "value": "Sun, 06 Jan 2019 22:00:11 GMT" }, { "name": "connection", @@ -64,11 +61,11 @@ }, { "name": "etag", - "value": "\"5be0a150-175\"" + "value": "\"5c327a6b-175\"" }, { "name": "expires", - "value": "Mon, 10 Dec 2018 19:39:06 GMT" + "value": "Thu, 31 Jan 2019 19:00:57 GMT" }, { "name": "cache-control", @@ -89,8 +86,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2018-12-03T19:39:01.830Z", - "time": 154, + "startedDateTime": "2019-01-24T19:00:31.717Z", + "time": 25959, "timings": { "blocked": -1, "connect": -1, @@ -98,7 +95,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 154 + "wait": 25959 } } ], diff --git a/yarn.lock b/yarn.lock index 7605c1a6..073c11c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4104,7 +4104,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chai@^4.2.0: +chai@^4.1.2, chai@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== @@ -5012,6 +5012,11 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" +deep-equal@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -10488,6 +10493,21 @@ nocache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" +nock@^10.0.6: + version "10.0.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" + integrity sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w== + dependencies: + chai "^4.1.2" + debug "^4.1.0" + deep-equal "^1.0.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.5" + mkdirp "^0.5.0" + propagate "^1.0.0" + qs "^6.5.1" + semver "^5.5.0" + node-fetch-npm@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" @@ -11517,6 +11537,11 @@ prop-types@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" +propagate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" + integrity sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk= + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -11641,7 +11666,7 @@ qs@6.5.2, qs@^6.4.0, qs@~6.5.1, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" -qs@^6.6.0: +qs@^6.5.1, qs@^6.6.0: version "6.6.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.6.0.tgz#a99c0f69a8d26bf7ef012f871cdabb0aee4424c2" integrity sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==