Permalink
Browse files

now reply supports file and json

  • Loading branch information...
1 parent 31a500c commit 3b37dec8c5e2c2af9485854a5925f9cbae8b306c @pgte pgte committed Sep 22, 2011
Showing with 149 additions and 14 deletions.
  1. +61 −6 README.md
  2. +1 −0 assets/reply_file_1.txt
  3. +20 −3 lib/scope.js
  4. +67 −5 tests/test_intercept.js
View
@@ -6,16 +6,56 @@ Nock can be used to test modules that perform HTTP requests in isolation.
For instance, if a module performs HTTP requests to a CouchDB server or makes HTTP requests to the Amazon API, you can test that module in isolation.
-## Install
+# Install
$ npm install nock
-## Use
+# Use
On your test, you can setup your mocking object like this:
var nock = require('nock');
+ var couchdb = nock('http://myapp.iriscouch.com')
+ .get('/users/1')
+ .reply(200, {_id: "123ABC", _rev: "946B7D1C", username: 'pgte', email: 'pedro.teixeira@gmail.com'});
+
+This setup says that we will intercept every HTTP call to `http://myapp.iriscouch.com`.
+
+It will intercept an HTTP GET request to '/users/1' and reply with a status 404.
+
+Then the test can call the module, and the module will do the HTTP requests.
+
+## Specifying replies
+
+You can specify the return status code for a path on the first argument of reply like this:
+
+ var couchdb = nock('http://myapp.iriscouch.com')
+ .get('/users/1')
+ .reply(404);
+
+You can also specify the reply body as a string:
+
+var couchdb = nock('http://www.google.com')
+ .get('/')
+ .reply(200, "Hello from Google!");
+
+as a JSON-encoded object:
+
+var couchdb = nock('http://myapp.iriscouch.com')
+ .get('/')
+ .reply(200, {username: 'pgte', email: 'pedro.teixeira@gmail.com', _id: "4324243fsd"});
+
+or even as a file:
+
+var couchdb = nock('http://myapp.iriscouch.com')
+ .get('/')
+ .replyWithFile(200, __dirname + '/replies/user.json');
+
+## Chaining
+
+You can chain behaviour like this:
+
var couchdb = nock('http://myapp.iriscouch.com')
.get('/users/1')
.reply(404)
@@ -24,10 +64,25 @@ On your test, you can setup your mocking object like this:
.get('/users/123ABC')
.reply(200, {_id: "123ABC", _rev: "946B7D1C", username: 'pgte', email: 'pedro.teixeira@gmail.com'});
-This setup says that we will intercept every call to
-Then the test can call the module, and the module will do the HTTP requests.
+# Expectations
+
+Every time an HTTP request is performed for a scope that is mocked, Nock expects to find a handler for it. If it doesn't, it will throw an error.
+
+Calls to nock() return a scope which you can assert by calling `scope.done()`. This will assert that all specified calls on that scope were performed.
+
+Example:
+
+ var google = nock('http://google.com')
+ .get('/')
+ .reply(200, 'Hello from Google!');
+
+ // do some stuff
+
+ setTimeout(function() {
+ google.done(); // will throw an assertion error if meanwhile a "GET http://google.com" was not performed.
+ });
-Every HTTP request to `myapp.iriscouch.com` will be intercepted and played according to what you specified.
+# How does it work?
-Any request that is not expected
+Nock works by overriding Node's http.request function.
View
@@ -0,0 +1 @@
+Hello from the file!
View
@@ -1,4 +1,5 @@
var path = require('path')
+ , fs = require('fs')
, globalIntercept = require('./intercept')
, assert = require('assert')
@@ -16,22 +17,37 @@ function startScope(basePath) {
function remove(key, interceptor) {
var arr = interceptors[key];
- arr.splice(arr.indexOf(interceptor), 1);
- if (arr.length === 0) { delete interceptors[key]; }
+ if (arr) {
+ arr.splice(arr.indexOf(interceptor), 1);
+ if (arr.length === 0) { delete interceptors[key]; }
+ }
}
function intercept(uri, method, requestBody) {
var key = method.toUpperCase() + ' ' + basePath + uri;
- if (requestBody) { key += (' ' + requestBody); }
+ if (requestBody) { key += (' ' + requestBody); }
function reply(statusCode, body, headers) {
this.statusCode = statusCode;
+
+ if (typeof(body) !== 'string') {
+ try {
+ body = JSON.stringify(body);
+ } catch(err) {
+ throw new Error('Error encoding response body into JSON');
+ }
+ }
+
this.body = body;
this.headers = headers;
add(key, this);
return scope;
}
+ function replyWithFile(statusCode, filePath, headers) {
+ return reply.call(this, statusCode, fs.readFileSync(filePath, 'utf8'), headers);
+ }
+
function match(options, body) {
var method = options.method || 'GET';
var matchKey = method + ' http://' + options.host + options.path;
@@ -46,6 +62,7 @@ function startScope(basePath) {
var interceptor = {
_key: key
, reply: reply
+ , replyWithFile: replyWithFile
, discard: discard
, match: match
};
View
@@ -69,7 +69,7 @@ tap.test("not mocked should work in http", function(t) {
t.end();
});
-tap.test("post works", function(t) {
+tap.test("post", function(t) {
var dataCalled = false;
var scope = nock('http://www.google.com')
@@ -108,7 +108,7 @@ tap.test("body data is differentiating", function(t) {
t.end();
});
-tap.test("chaining works", function(t) {
+tap.test("chaining", function(t) {
var repliedCount = 0;
var scope = nock('http://www.spiffy.com')
.get('/')
@@ -124,7 +124,7 @@ tap.test("chaining works", function(t) {
t.end();
}
- t.test("post works", function(t) {
+ t.test("post", function(t) {
var req = http.request({
host: "www.spiffy.com"
, method: 'POST'
@@ -148,7 +148,7 @@ tap.test("chaining works", function(t) {
req.end();
});
- t.test("get works", function(t) {
+ t.test("get", function(t) {
var req = http.request({
host: "www.spiffy.com"
, method: 'GET'
@@ -174,7 +174,7 @@ tap.test("chaining works", function(t) {
});
});
-tap.test("encoding works", function(t) {
+tap.test("encoding", function(t) {
var dataCalled = false
var scope = nock('http://www.encoderz.com')
@@ -204,4 +204,66 @@ tap.test("encoding works", function(t) {
});
req.end();
+});
+
+tap.test("reply with file", function(t) {
+ var dataCalled = false
+
+ var scope = nock('http://www.filereplier.com')
+ .get('/')
+ .replyWithFile(200, __dirname + '/../assets/reply_file_1.txt')
+ .get('/test')
+ .reply(200, 'Yay!');
+
+ var req = http.request({
+ host: "www.filereplier.com"
+ , path: '/'
+ , port: 80
+ }, function(res) {
+
+ t.equal(res.statusCode, 200);
+ res.on('end', function() {
+ t.ok(dataCalled);
+ t.end();
+ });
+ res.on('data', function(data) {
+ dataCalled = true;
+ t.equal(data.toString(), "Hello from the file!", "response should match");
+ });
+
+ });
+
+ req.end();
+
+});
+
+tap.test("reply with JSON", function(t) {
+ var dataCalled = false
+
+ var scope = nock('http://www.jsonreplier.com')
+ .get('/')
+ .reply(200, {hello: "world"});
+
+ var req = http.request({
+ host: "www.jsonreplier.com"
+ , path: '/'
+ , port: 80
+ }, function(res) {
+
+ res.setEncoding('utf8');
+ t.equal(res.statusCode, 200);
+ res.on('end', function() {
+ t.ok(dataCalled);
+ scope.done();
+ t.end();
+ });
+ res.on('data', function(data) {
+ dataCalled = true;
+ t.equal(data.toString(), '{"hello":"world"}', "response should match");
+ });
+
+ });
+
+ req.end();
+
});

0 comments on commit 3b37dec

Please sign in to comment.