I'm running my test suite using mocha
, via gulp-jsx-coverage
and gulp-mocha
. All my tests run and pass/fail as expected. However, some of my modules being tested make HTTP requests to my API via the superagent
library.
When in development, I'm also running my API at localhost:3000
alongside my client-side app, and so that is the URL my client-side tests are attempting to access. When testing, though, the API is usually not running. This results in the following error any time a request gets through:
Error in plugin 'gulp-mocha'
Message:
connect ECONNREFUSED
Details:
code: ECONNREFUSED
errno: ECONNREFUSED
syscall: connect
domainEmitter: [object Object]
domain: [object Object]
domainThrown: false
Stack:
Error: connect ECONNREFUSED
at exports._errnoException (util.js:746:11)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:983:19)
I've tried stubbing all of the methods on the superagent
(aliased as request
) library in a global helper, like so:
function httpStub() {
return {
withCredentials: () => {
return { end: () => {} };
}
};
};
beforeEach(function() {
global.sandbox = sinon.sandbox.create();
global.getStub = global.sandbox.stub(request, 'get', httpStub);
global.putStub = global.sandbox.stub(request, 'put', httpStub);
global.patchStub = global.sandbox.stub(request, 'patch', httpStub);
global.postStub = global.sandbox.stub(request, 'post', httpStub);
global.delStub = global.sandbox.stub(request, 'del', httpStub);
});
afterEach(function() {
global.sandbox.restore();
});
But for some reason, when some tests are encountered the methods aren't stubbed and so I reach the ECONNREFUSED
error. I've triple checked, and no where am I restoring the sandbox or any stubs.
Is there either a way to fix the problem I'm running into, or a cleaner solution for this overall?
The problem might might be caused by not doing asynchronous stuff properly in your test. Imagine following example:
it('is BAD asynchronous test', () => {
do_something()
do_something_else()
return do_something_async(/* callback */ () => {
problematic_call()
})
})
When Mocha finds such a test it executes (synchronously) do_something
, do_something_else
and do_something_async
. In that moment, from Mochas perspective the test is over, Mocha executes afterEach() for it (what is bad, the problematic_call
is still yet to be called!) and (what is even worse), it start running the next test!
Now, obviously, running tests (and beforeEach and afterEach) in a parallel manner can lead to really strange and unpredictable results, so it's no surprise something got wrong (probably afterEach was called in the middle of some test which lead to unstubbing the environment)
What to do with it:
Always signal to Mocha, when your test ends. This can be done either by returning a Promise object, or, by calling done
callback:
it('is BAD asynchronous test', (done) => {
do_something()
do_something_else()
return do_something_async(/* callback */ () => {
problematic_call()
done()
})
})
https://mochajs.org/
This way Mocha 'knows' when your test ends and only then it runs the next test.
request
has already been required by your application, so it doesn't matter whether or not your stub it in your tests.
You need to use something like rewire
and replace the request
required by your application with your stubbed version.
Something like this should help
var request = require('superagent'),
rewire = require('rewire'),
sinon = require('sinon'),
application = rewire('your-app'),
rewiredRequest;
function httpStub() {
return {
withCredentials: () => {
return { end: () => {} };
}
};
};
beforeEach(function() {
var requestStub = {
get: httpStub,
put: httpStub,
patch: httpStub,
post: httpStub,
del: httpStub
};
// rewiredRequest is a function that will revert the rewiring
rewiredRequest = application.__set__({
request: requestStub
});
});
afterEach(function() {
rewiredRequest();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With