Skip to content

Commit

Permalink
Merge pull request #19 from ikhilko/master
Browse files Browse the repository at this point in the history
Extend functionality
  • Loading branch information
A committed Oct 14, 2015
2 parents 36ea0c6 + 643f998 commit dd3188a
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 20 deletions.
73 changes: 58 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/
var pathtoRegexp = require('path-to-regexp');


/**
* Expose public API
*/
Expand All @@ -14,6 +13,7 @@ mock.get = defineRoute.bind(null, 'GET');
mock.post = defineRoute.bind(null, 'POST');
mock.put = defineRoute.bind(null, 'PUT');
mock.del = defineRoute.bind(null, 'DELETE');
mock.patch = defineRoute.bind(null, 'PATCH');

/**
* Request timeout
Expand All @@ -26,12 +26,39 @@ mock.timeout = 0;
*/
var routes = [];

/**
* Original superagent methods
* @type {{}}
*/
var originalMethods = {};

/**
* Unregister all routes
*/
mock.clearRoutes = function() {
routes.splice(0, routes.length)
}
};

/**
* Map api method to http method
*/
var methodsMapping = {
get: 'GET',
post: 'POST',
put: 'PUT',
del: 'DELETE',
patch: 'PATCH'
};

/**
* Unregister specific route
*/
mock.clearRoute = function(method, url) {
method = methodsMapping[method] || method;
routes = routes.filter(function(route) {
return !(route.url === url && route.method === method);
});
};

/**
* Mock
Expand All @@ -51,16 +78,18 @@ function mock(superagent) {
}
};

// Patch superagent
patch(superagent, 'get', 'GET', state);
patch(superagent, 'post', 'POST', state);
patch(superagent, 'put', 'PUT', state);
patch(superagent, 'del', 'DELETE', state);
// patch api methods (http)
for (var method in methodsMapping) {
if (methodsMapping.hasOwnProperty(method)) {
var httpMethod = methodsMapping[method];
patch(superagent, method, httpMethod, state);
}
}

var reqProto = superagent.Request.prototype;

// Patch Request.end()
var oldEnd = superagent.Request.prototype.end;
var oldEnd = originalMethods.end = superagent.Request.prototype.end;
reqProto.end = function(cb) {
var current = state.current;
if (current) {
Expand All @@ -77,10 +106,10 @@ function mock(superagent) {
};

// Patch Request.set()
var oldSet = reqProto.set;
var oldSet = originalMethods.set = reqProto.set;
reqProto.set = function(key, val) {
if (!state.current) {
return oldSet(key, val);
return oldSet.call(this, key, val);
}
// Recursively set keys if passed an object
if (isObject(key)) {
Expand All @@ -94,22 +123,36 @@ function mock(superagent) {
}
state.request.headers[key.toLowerCase()] = val;
return this;
}
};

// Patch Request.send()
var oldSend = reqProto.send
var oldSend = originalMethods.send = reqProto.send;
reqProto.send = function(data) {
if (!state.current) {
return oldSend(data);
return oldSend.call(this, data);
}
state.request.body = mergeObjects(state.current.body, data);
return this;
}
};

return mock; // chaining

}

mock.unmock = function(superagent) {
['get', 'post', 'put', 'patch', 'del'].forEach(function(method) {
superagent[method] = originalMethods[method];
});

var reqProto = superagent.Request.prototype;

['end', 'set', 'send'].forEach(function(method) {
reqProto[method] = originalMethods[method];
});

delete superagent._patchedBySuperagentMocker;
};

/**
* find route that matched with url and method
* TODO: Remove data
Expand Down Expand Up @@ -137,7 +180,7 @@ function defineRoute(method, url, handler) {
* Patch superagent method
*/
function patch(superagent, prop, method, state) {
var old = superagent[prop];
var old = originalMethods[prop] = superagent[prop];
superagent[prop] = function (url, data, fn) {
state.current = match(method, url, data);
state.request = {
Expand Down
20 changes: 19 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ request
;
```

`mock.put()` method works in a similar way.
`mock.put()`, `mock.patch()` methods works in a similar way.

### Teardown

Expand Down Expand Up @@ -124,6 +124,24 @@ define('My API module', function(){
})
```

Or you can remove only one specified route (by method and url)

```js
// to register route
mock.get('/me', function(){done()})

...

// to remove registered handler
mock.clearRoute('get', '/me');

```

### Rollback library effect

In some cases it will be useful to remove patches from superagent lib after using mocks.
In this cases you can use ```mock.unmock()``` method, that will rollback all patches that ```mock(superagent)``` call make.

## License

MIT © [Shuvalov Anton](http://shuvalov.info)
Expand Down
47 changes: 43 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ var mock = process.env.SM_COV
? require('./index-cov')(request)
: require('./index')(request);


describe('superagent mock', function() {

beforeEach(function() {
Expand Down Expand Up @@ -63,6 +62,20 @@ describe('superagent mock', function() {
;
});

it('should mock for patch', function(done) {
mock.patch('/topics/:id', function(req) {
return { id: req.params.id, content: req.body.content };
});
request
.patch('/topics/7', { id: 7, content: 'hello world, bitch!11' })
.end(function(_, data) {
data.should.have.property('id', '7');
data.should.have.property('content', 'hello world, bitch!11');
done();
})
;
});

it('should mock for delete', function(done) {
mock.del('/topics/:id', function(req) {
return { id: req.params.id, content: req.body.content };
Expand Down Expand Up @@ -139,6 +152,29 @@ describe('superagent mock', function() {
});
});

it('should clear registered specific route', function(done) {
mock
.get('/topics', noop)
.get('/posters', function() {
return { id: 7 };
});
mock.clearRoute('get', '/topics');
request
.get('/topics')
.end(function(err, res) {
should.throws(function() {
should.ifError(err);
}, /ECONNREFUSED/);

request
.get('/posters')
.end(function(_, data) {
data.should.have.property('id', 7);
done();
});
});
});

it('should provide error when method throws', function(done) {
var error = Error('This should be in the callback!');
mock.get('http://example.com', function(req) {
Expand Down Expand Up @@ -217,7 +253,7 @@ describe('superagent mock', function() {
return req.body;
});
request
.post('/topics/5', { content: 'Hello Universe'})
.post('/topics/5', { content: 'Hello Universe' })
.send({ content: 'Hello world', title: 'Yay!' })
.end(function(_, data) {
data.should.have.property('title', 'Yay!');
Expand All @@ -227,12 +263,15 @@ describe('superagent mock', function() {
;
});

it('should remove patches by unmock()', function() {
mock.unmock(request);
(request._patchedBySuperagentMocker === void 0).should.be.true;
});

});

});



/**
* Just noop
*/
Expand Down

0 comments on commit dd3188a

Please sign in to comment.