I'm writing tests for a small REST library that implements OAuth's refresh grant on top of the request library. As part of it's functionality, it's providing a retry function that has something like this in rest.js
:
const auth = require('./auth');
const request = require('request');
function retry(headers, responseHandler) {
headers.auth.bearer = auth.getToken();
request(headers, function(err, resp) {
if (resp.error && resp.error == 'invalid_token') {
return auth.renew(function(e, r) { retry(headers, responseHandler); });
}
// handle happy case
});
});
What auth.renew
does is posting to the token provider with the information in headers
and internally known refresh token. The important bit is that it does this by using request.post
, passing the recursive event handler down to the request library.
Naturally, when I test this, I don't want outgoing HTTP calls. So I use sinon to stub them out:
const requestStub = sinon.stub(),
rest = proxyquire('./rest', { 'request': requestStub }),
authFail = { error: 'invalid_token' },
authSuccess = { token: '123' };
describe('#retry', () => {
it('calls retry twice on failed auth', () => {
requestStub.yields(null, authFail);
requestStub.post = sinon.stub().yields(null, authSuccess);
retry({}, () => {});
sinon.assert.calledTwice(requestStub);
});
});
The problem is that auth.renew
happily goes on to require('request')
on it's own and thus never seeing my stub. So I guess my question is:
How do I make auth
use my stubbed request
instead of its own?
I know sinon can stub XHR, but that seems like a lot of low-level effort for what I want.
So the solution I came up with was to replace the entire auth.renew
method, so the thing looks like this:
const requestStub = sinon.stub(),
rest = proxyquire('./rest', { 'request': requestStub,
'./auth': {
renew: function(callback) {
requestStub.yields(null, authSuccess);
callback();
}
}),
authFail = { error: 'invalid_token' },
authSuccess = { token: '123' };
describe('#retry', () => {
it('calls retry twice on failed auth', () => {
requestStub.yields(null, authFail);
retry({}, () => {});
sinon.assert.calledTwice(requestStub);
});
});