I'm trying to mock request-promise in a test using Sinon. As far as I can tell, Sinon mocks methods of objects, and yet request-promise simply returns a function. Is there any way to mock a single required function?
var rp = require('request-promise');
var User = require('../../models/user');
// this works
sinon.stub(User, 'message', function() {});
// This is what I'd like to do to request-promise
sinon.stub(rp, function() {});
I've also looked into mockrequire and proxyquire but I think they both run into similar issues.
I'm trying to mock request-promise in a test using Sinon. As far as I can tell, Sinon mocks methods of objects, and yet request-promise simply returns a function. Is there any way to mock a single required function?
var rp = require('request-promise');
var User = require('../../models/user');
// this works
sinon.stub(User, 'message', function() {});
// This is what I'd like to do to request-promise
sinon.stub(rp, function() {});
I've also looked into mockrequire and proxyquire but I think they both run into similar issues.
Share Improve this question asked Aug 18, 2015 at 5:07 thekevinscottthekevinscott 5,42310 gold badges46 silver badges57 bronze badges2 Answers
Reset to default 5The following example should clear things up for you. By using proxyquire, you can wrap request-promise
and avoid stubbing .post
, .get
, .call
, etc. Much cleaner in my opinion.
myModule.js
:
'use strict';
const rp = require('request-promise');
class MyModule {
/**
* Sends a post request to localhost:8080 to create a character.
*/
static createCharacter(data = {}) {
const options = {
method: 'POST',
uri: 'http://localhost:8080/create-character',
headers: {'content-type': 'application/json'},
body: data,
};
return rp(options);
}
}
module.exports = MyModule;
myModule.spec.js
:
'use strict';
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const requestPromiseStub = sinon.stub();
const MyModule = proxyquire('./myModule', {'request-promise': requestPromiseStub});
describe('MyModule', () => {
it('#createCharacter', (done) => {
// Set the mocked response we want request-promise to respond with
const responseMock = {id: 2000, firstName: 'Mickey', lastName: 'Mouse'};
requestPromiseStub.resolves(responseMock);
MyModule.createCharacter({firstName: 'Mickey', lastName: 'Mouse'})
.then((response) => {
// add your expects / asserts here. obviously this doesn't really
// prove anything since this is the mocked response.
expect(response).to.have.property('firstName', 'Mickey');
expect(response).to.have.property('lastName', 'Mouse');
expect(response).to.have.property('id').and.is.a('number');
done();
})
.catch(done);
});
});
I found a (sort of) solution here.
Basically, you piggyback off of call
(apply
would also work):
// models/user.js
var rp = require('request-promise');
var User = {
save: function(data) {
return rp.call(rp, {
url: ...,
data: data
});
}
}
module.exports = User;
// test/user.js
var rp = require('request-promise');
var User = require('../../models/user');
describe('User', function() {
it('should check that save passes data through', function() {
sinon.stub(rp, 'call', function(data) {
// check data here
});
User.save({ foo: 'bar' });
});
});
It gets the job done, although I'm not a fan of having to do rp.call
everywhere, so I'm still holding out hope for a better solution.