Skip to content
Browse files

Merge pull request #148 from SoftwareMarbles/add-output-objects-to-re…

…corder

Add output objects to recorder
  • Loading branch information...
2 parents 68a9313 + b2fc8be commit b46466715d43673e935c123642aac28aae7a6e90 @svnlto svnlto committed
Showing with 178 additions and 20 deletions.
  1. +30 −1 README.md
  2. +74 −15 lib/recorder.js
  3. +74 −4 tests/test_recorder.js
View
31 README.md
@@ -467,7 +467,9 @@ nock.recorder.rec();
If you just want to capture the generated code into a var as an array you can use:
```js
-nock.recorder.rec(true); // :no_output = true
+nock.recorder.rec({
+ dont_print: true
+});
// ... some HTTP calls
var nockCalls = nock.recorder.play();
```
@@ -478,6 +480,33 @@ Copy and paste that code into your tests, customize at will, and you're done!
(Remember that you should do this one test at a time).
+In case you want to generate the code yourself or pass the test data in some other way, you can pass the `output_objects` option to `rec`:
+
+```js
+nock.recorder.rec({
+ output_objects: true
+});
+// ... some HTTP calls
+var nockCallObjects = nock.recorder.play();
+```
+
+The returned call objects have the following properties:
+ `scope` - the scope of the call (e.g. `https://github.com`)
+
+ `port` - the port of the call (e.g. `80`, `443` or `undefined` if the HTTP request didn't have `options.port` defined)
+
+ `method` - the HTTP verb of the call (e.g. `'GET'`)
+
+ `path` - the path of the call (e.g. `'/pgte/nock'`)
+
+ `body` - the body of the call, if any
+
+ `reply` - the HTTP status as string of the reply (e.g. `'200'`)
+
+ `response` - the body of the reply
+
+ `headers` - the headers of the reply
+
# How does it work?
Nock works by overriding Node's `http.request` function. Also, it overrides `http.ClientRequest` too to cover for modules that use it directly.
View
89 lib/recorder.js
@@ -8,34 +8,83 @@ var SEPARATOR = '\n<<<<<<-- cut here -->>>>>>\n';
var outputs = [];
-function generateRequestAndResponse(body, options, res, datas) {
- var requestBody = body.map(function(buffer) {
+function getScope(options) {
+
+ var scope = [];
+ if (options._https_) {
+ scope.push('https://');
+ } else {
+ scope.push('http://');
+ }
+ scope.push(options.host);
+ if(options.port) {
+ scope.push(':');
+ scope.push(options.port);
+ }
+
+ return scope.join('');
+
+}
+
+function getMethod(options) {
+
+ return (options.method || 'GET');
+
+}
+
+function getRequestBody(body) {
+
+ var joinedBody = body.map(function(buffer) {
return buffer.toString('utf8');
}).join('');
- var responseBody = datas.map(function(buffer) {
+ try {
+ return JSON.parse(joinedBody);
+ } catch(err) {
+ return joinedBody;
+ }
+
+}
+
+function getResponseBody(body) {
+
+ return body.map(function(buffer) {
return buffer.toString('utf8');
}).join('');
+}
+
+function generateRequestAndResponseObject(body, options, res, datas) {
+
+ return {
+ scope: getScope(options),
+ port: options.port,
+ method: getMethod(options),
+ path: options.path,
+ body: getRequestBody(body),
+ reply: res.statusCode.toString(),
+ response: getResponseBody(datas),
+ headers: res.headers ? inspect(res.headers) : undefined
+ };
+
+}
+
+function generateRequestAndResponse(body, options, res, datas) {
+
+ var requestBody = getRequestBody(body);
+ var responseBody = getResponseBody(datas);
+
var ret = [];
ret.push('\nnock(\'');
- if (options._https_) {
- ret.push('https://');
- } else {
- ret.push('http://');
- }
- ret.push(options.host);
+ ret.push(getScope(options));
ret.push('\')\n');
ret.push(' .');
- ret.push((options.method || 'GET').toLowerCase());
+ ret.push(getMethod(options).toLowerCase());
ret.push('(\'');
ret.push(options.path);
ret.push("'");
if (requestBody) {
ret.push(', ');
- try {
- requestBody = JSON.parse(requestBody)
- } catch(err) {}
ret.push(JSON.stringify(requestBody));
}
ret.push(")\n");
@@ -53,7 +102,14 @@ function generateRequestAndResponse(body, options, res, datas) {
return ret.join('');
}
-function record(dont_print) {
+function record(options) {
+
+ // Originaly the parameters was a dont_print boolean flag.
+ // To keep the existing code compatible we take that case into account.
+ var dont_print = (typeof options === 'boolean' && options)
+ || (typeof options === 'object' && options.dont_print);
+ var output_objects = typeof options === 'object' && options.output_objects;
+
[http, https].forEach(function(module) {
var oldRequest = module.request;
module.request = function(options, callback) {
@@ -71,7 +127,10 @@ function record(dont_print) {
if (module === https) { options._https_ = true; }
res.once('end', function() {
- var out = generateRequestAndResponse(body, options, res, datas);
+ var out = !output_objects ?
+ generateRequestAndResponse(body, options, res, datas) :
+ generateRequestAndResponseObject(body, options, res, datas);
+
outputs.push(out);
if (! dont_print) { console.log(SEPARATOR + out + SEPARATOR); }
});
View
78 tests/test_recorder.js
@@ -16,20 +16,54 @@ tap.test('records', function(t) {
nock.recorder.rec(true);
var req = http.request(options, function(res) {
res.resume();
- cb1 = true
+ cb1 = true;
var ret;
res.once('end', function() {
nock.restore();
ret = nock.recorder.play();
t.equal(ret.length, 1);
t.type(ret[0], 'string');
- t.equal(ret[0].indexOf("\nnock('http://google.com')\n .post('/', \"ABCDEF\")\n .reply("), 0);
+ t.equal(ret[0].indexOf("\nnock('http://google.com:80')\n .post('/', \"ABCDEF\")\n .reply("), 0);
t.end();
});
});
req.end('ABCDEF');
});
+tap.test('records objects', function(t) {
+ nock.restore();
+ nock.recorder.clear();
+ t.equal(nock.recorder.play().length, 0);
+ var cb1 = false
+ , options = { method: 'POST'
+ , host:'google.com'
+ , path:'/' }
+ ;
+
+ nock.recorder.rec({
+ dont_print: true,
+ output_objects: true
+ });
+ var req = http.request(options, function(res) {
+ res.resume();
+ cb1 = true;
+ var ret;
+ res.once('end', function() {
+ nock.restore();
+ ret = nock.recorder.play();
+ t.equal(ret.length, 1);
+ var ret = ret[0];
+ t.type(ret, 'object');
+ t.equal(ret.scope.indexOf("http://google.com"), 0);
+ t.equal(ret.method.indexOf("POST"), 0);
+ t.ok(typeof(ret.reply) !== 'undefined');
+ t.ok(typeof(ret.response) !== 'undefined');
+ t.ok(typeof(ret.port) === 'undefined');
+ t.end();
+ });
+ });
+ req.end('ABCDEF');
+});
tap.test('checks if callback is specified', function(t) {
var options = {
@@ -63,10 +97,46 @@ tap.test('when request body is json, it goes unstringified', function(t) {
ret = nock.recorder.play();
t.ok(ret.length >= 1);
ret = ret[1] || ret[0];
- t.equal(ret.indexOf("\nnock('http://www.google.com')\n .post('/', {\"a\":1,\"b\":true})\n .reply("), 0);
+ t.equal(ret.indexOf("\nnock('http://www.google.com:80')\n .post('/', {\"a\":1,\"b\":true})\n .reply("), 0);
+ t.end();
+ })
+ });
+
+ request.end(JSON.stringify(payload));
+});
+
+tap.test('when request body is json, it goes unstringified in objects', function(t) {
+ var payload = {a: 1, b: true};
+ var options = {
+ method: 'POST',
+ host: 'www.google.com',
+ path: '/',
+ port: 80
+ };
+
+ nock.restore();
+ nock.recorder.clear();
+ nock.recorder.rec({
+ dont_print: true,
+ output_objects: true
+ });
+
+ var request = http.request(options, function(res) {
+ res.resume();
+ res.once('end', function() {
+ ret = nock.recorder.play();
+ t.ok(ret.length >= 1);
+ ret = ret[1] || ret[0];
+ t.type(ret, 'object');
+ t.equal(ret.scope.indexOf("http://www.google.com"), 0);
+ t.equal(ret.port, 80);
+ t.equal(ret.method.indexOf("POST"), 0);
+ t.ok(ret.body && ret.body.a && ret.body.a === payload.a && ret.body.b && ret.body.b === payload.b);
+ t.ok(typeof(ret.reply) !== 'undefined');
+ t.ok(typeof(ret.response) !== 'undefined');
t.end();
})
});
request.end(JSON.stringify(payload));
-});
+});

0 comments on commit b464667

Please sign in to comment.
Something went wrong with that request. Please try again.