Skip to content

Commit

Permalink
feat(adapter-node-http): Upgrade nock to v11.x (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
offirgolan committed Nov 21, 2019
1 parent ee25c77 commit 5d42cbd
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 186 deletions.
3 changes: 1 addition & 2 deletions packages/@pollyjs/adapter-node-http/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@
"@pollyjs/adapter": "^2.6.3",
"@pollyjs/utils": "^2.6.3",
"lodash-es": "^4.17.11",
"nock": "^10.0.6",
"semver": "^6.1.1"
"nock": "^11.7.0"
},
"devDependencies": {
"@pollyjs/core": "^2.6.3",
Expand Down
6 changes: 3 additions & 3 deletions packages/@pollyjs/adapter-node-http/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import createNodeConfig from '../../../scripts/rollup/node.config';

export default createNodeConfig({
external: ['http', 'https', 'url', 'stream']
});
import { external } from './rollup.config.shared';

export default createNodeConfig({ external });
10 changes: 10 additions & 0 deletions packages/@pollyjs/adapter-node-http/rollup.config.shared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const external = [
'http',
'https',
'url',
'stream',
'timers',
'tty',
'util',
'os'
];
8 changes: 5 additions & 3 deletions packages/@pollyjs/adapter-node-http/rollup.config.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import createNodeTestConfig from '../../../scripts/rollup/node.test.config';
import createJestTestConfig from '../../../scripts/rollup/jest.test.config';

const external = ['http', 'https', 'url', 'stream', 'crypto'];
import { external } from './rollup.config.shared';

const testExternal = [...external, 'crypto'];

export default [
createNodeTestConfig({ external }),
createJestTestConfig({ external })
createNodeTestConfig({ external: testExternal }),
createJestTestConfig({ external: testExternal })
];
74 changes: 39 additions & 35 deletions packages/@pollyjs/adapter-node-http/src/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import http from 'http';
import https from 'https';
import URL from 'url';
import { Readable } from 'stream';
import { URL } from 'url';
import { Readable as ReadableStream } from 'stream';

import nock from 'nock';
import semver from 'semver';
import {
normalizeClientRequestArgs,
isUtf8Representable,
isContentEncoded,
isJSONContent
} from 'nock/lib/common';
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';
import urlToOptions from './utils/url-to-options';

const IS_STUBBED = Symbol();
const REQUEST_ARGUMENTS = new WeakMap();
Expand Down Expand Up @@ -63,16 +66,26 @@ export default class HttpAdapter extends Adapter {
interceptor.intercept(/.*/, m).reply(function(_, body, respond) {
const { req, method } = this;
const { headers } = req;
const parsedArguments = parseRequestArguments(
const parsedArguments = normalizeClientRequestArgs(
...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);
const contentType = (headers['content-type'] || '').toString();
const isMultiPart = contentType.includes('multipart');

if (body) {
if (isMultiPart && Buffer.isBuffer(body)) {
// Nock can return a hex-encoded body multipart/form-data
if (!isUtf8Representable(body)) {
body = Buffer.from(body, 'hex');
}

body = body.toString();
} else if (isJSONContent(headers)) {
// Nock will parse json content into an object. We have our own way
// of dealing with json content so convert it back to a string.
body = JSON.stringify(body);
}
}

adapter.handleRequest({
Expand Down Expand Up @@ -109,16 +122,13 @@ export default class HttpAdapter extends Adapter {
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.
// 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);

function parseArgs() {
const args = normalizeClientRequestArgs(...arguments);

if (moduleName === 'https') {
args.options = {
Expand All @@ -133,21 +143,19 @@ export default class HttpAdapter extends Adapter {
}

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);
module.get = function _get() {
const { options, callback } = parseArgs(...arguments);

return get(options, callback);
};
}
return get(options, callback);
};
});
}

Expand All @@ -160,7 +168,7 @@ export default class HttpAdapter extends Adapter {
...options,
method,
headers: { ...headers },
...URL.parse(pollyRequest.url)
...urlToOptions(new URL(pollyRequest.url))
});

const chunks = this.getChunksFromBody(body, headers);
Expand Down Expand Up @@ -199,18 +207,14 @@ export default class HttpAdapter extends Adapter {
if (error) {
// If an error was received then forward it over to nock so it can
// correctly handle it.
// https://github.com/nock/nock/blob/v10.0.6/lib/request_overrider.js#L394-L397
respond(error);

// This allows the consumer to handle the error gracefully
req.emit('error', error);

return;
}

const { statusCode, body, headers } = pollyRequest.response;
const chunks = this.getChunksFromBody(body, headers);
const stream = new Readable();
const stream = new ReadableStream();

// Expose the response data as a stream of chunks since
// it could contain encoded data which is needed
Expand Down Expand Up @@ -262,7 +266,7 @@ export default class HttpAdapter extends Adapter {
// 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');
return buffer.toString(isUtf8Representable(buffer) ? 'utf8' : 'hex');
}

getChunksFromBody(body, headers) {
Expand All @@ -287,6 +291,6 @@ export default class HttpAdapter extends Adapter {
// 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')];
return [Buffer.from(buffer, isUtf8Representable(buffer) ? 'utf8' : 'hex')];
}
}
34 changes: 0 additions & 34 deletions packages/@pollyjs/adapter-node-http/src/utils/is-binary-buffer.js

This file was deleted.

This file was deleted.

This file was deleted.

31 changes: 31 additions & 0 deletions packages/@pollyjs/adapter-node-http/src/utils/url-to-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Utility function that converts a URL object into an ordinary
* options object as expected by the http.request and https.request APIs.
*
* This was copied from Node's source
* https://github.com/nodejs/node/blob/908292cf1f551c614a733d858528ffb13fb3a524/lib/internal/url.js#L1257
*/
export default function urlToOptions(url) {
const options = {
protocol: url.protocol,
hostname:
typeof url.hostname === 'string' && url.hostname.startsWith('[')
? url.hostname.slice(1, -1)
: url.hostname,
hash: url.hash,
search: url.search,
pathname: url.pathname,
path: `${url.pathname}${url.search || ''}`,
href: url.href
};

if (url.port !== '') {
options.port = Number(url.port);
}

if (url.username || url.password) {
options.auth = `${url.username}:${url.password}`;
}

return options;
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 5d42cbd

Please sign in to comment.