Assertion in event brake down Mocha when run programmatically - node.js

I have problem with Mocha.
If i run this programmaticaly from Jake Mocha brakes down and don't show nothing more than some errors stuff like:
AssertionError: There is a code 200 in response
at Socket.<anonymous> (/home/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
Runned from command line gives more expected results. That is:
19 passing (30ms)
7 failing
1) RTDB accepts connection with package and response with code 200 if correct package was send:
Uncaught AssertionError: There is a code 200 in response
at Socket.<anonymous> (/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
2) XYZ should be able to store GHJ for IJS:
Error: expected f...
...
The problem is following code:
test('accepts connection with package and response with code 400 ' +
'if wrong package was send', function (done) {
console.log('client connecting to server');
var message = '';
var client = net.connect(8122, 'localhost', function () {
client.write('Hello');
client.end();
} );
client.setEncoding('utf8');
client.on('data', function (data) {
message += data;
} );
client.on('end', function (data) {
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
done();
});
client.on('error', function(e) {
throw new Error('Client error: ' + e);
});
});
If I do
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
just after
var message = '';
Mocha fails correctly (I mean displaying errors etc.), So this is fault of asynch assertion done on event. How can I correct that? Thats real problem Because this test is first, and I get no clue where to look for source of problem (If there is any). Should I somehow catch this assertion error and pass it to Mocha?
EDIT:
Answer to comment how is Jake running Mocha - just like that:
var Mocha = require('mocha');
...
task("test", [], function() {
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
});
}, {async: true});

I'm assuming since you say "programmatically" that your Jakefile issues require("mocha") and then creates a Mocha object on which it calls the run method.
If this is the case, then the reason it does not work is because Jake and Mocha are working at cross purposes. When Mocha executes a test, it traps unhandled exceptions. Schematically, (omitting details that are not important) it is something like:
try {
test.run();
}
catch (ex) {
recordFailure();
}
It is at the call to test.run that the test is executed. For tests that are purely synchronous, no problem. When a test is asynchronous, the asynchronous callback which is part of the test cannot execute inside the try... catch block Mocha establishes. The test will launch the asynchronous operation and return immediately. At some point in the future, the asynchronous operation calls the callback. When this happens, Mocha is not able to catch the exception in the asynchronous operation with a try... catch block. How does it catch such exceptions then? It listens to uncaughtException events.
Now, the problem when Mocha is run in the same execution context as Jake is that Jake also wants to trap uncaught exceptions. Jake sometimes has to launch asynchronous operations and wants to trap cases where these operations fail, so it listens to uncaughtException too. It installs its listener first. So when an asynchronous Mocha test fails with a exception, Jake's listener's is called, which cause Jake to immediately stop execution. Mocha never gets a chance to act.
I don't see a clear way to make both Jake and Mocha cooperate when run in the same execution context. There might be a way to fiddle with the handlers but I doubt that there is a robust way to make it work. (By "robust" I mean a way which will ensure that every single error is trapped and attributed to the correct source.) The vm module might help segregate their contexts while keeping them in the same OS process.

Based on this answer: https://stackoverflow.com/a/9132271/2024650
In few words: I remove listener on uncaughtException in Jake. This allow Mocha to handle this uncaughtExceptions. At the end I add back this listener.
This solves my answer for now:
task("test", [], function() {
var originalExeption = process.listeners('uncaughtException').pop();
//!!!in node 0.10.X you should also check if process.removeListener isn't necessary!!!
console.log(originalExeption);
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
process.listeners('uncaughtException').push(originalExeption);
});
}, {async: true});

it seems that you are testing a HTTP server by connecting with TCP to it, (correct if i'm wrong) if thats the case here, you should just drop your current test, and use appropriate module to test an HTTP server or REST API there are plenty modules like Superagent .
You should try call client.end() after you have received your first data event, this way it will call assert after first header is received.
if you want to continuously send and test requests, have all you assert in the data event and call correct assert each time it receives the header you want to test, just remember that you must call done() when its supposed to finish, and that it can't be delayed for a long period of time, the request must be one after another.
Other than that you can use async module if you want to test chained requests ( one request depends on another and another and so on..), in some case its useful to raise the mocha timeout to more than 10000 (10secs) to give the async part some time to complete.

Related

mocha test failing with " MongoError: server sockets closed"

My mocha tests are failing with:
MongoError: server XXXX sockets closed
I have a workaround how to fix them:
const https = require('https');
const server = https.createServer(..);
close() {
mongoose.disconnect(); // <-------- I will comment this line
this.server.close();
};
I would comment out the line mongoose.disconnect(); and my test suite starts working. I would like to clean up after my tests too. Each of my test files recreates server and starts from the scratch. It seems like the error appears because there needs to be some 'waiting' before the next test file executes.
How can I correct this error?
Solution - Captain Hook to the rescue!
If I understand correctly, you wish to startup and cleanup your server after the tests. You also have a series of repetitive tasks you need to do before and after each test.
Mocha has the perfect solution for you: Say hello to Mr. Hook!
Mocha hooks are functions that you can run both before all tests, after all tests, or before each test and after each test:
https://mochajs.org/#hooks
The documentation is pretty complete and I really do recommend it. I your case however, since you are dealing with databases, you probably will be dealing with async hooks.
Sounds complex? Don't worry!
This is how normal sync hooks work:
describe('hooks', function() {
before(function() {
// runs before all tests in this block
});
after(function() {
// runs after all tests in this block
});
beforeEach(function() {
// runs before each test in this block
});
afterEach(function() {
// runs after each test in this block
});
//tests
it("This is a test", () => {
assert.equal(1, 1);
});
});
async hooks only have one difference: they have a parameter done, which is called once your task is finished. Lets assume that we are setting up a DB that takes 1.5 seconds to setup. We want to do this before all the tests, and we only want to do it once.
Let's assume this is our listen function from our DB:
const listen = callback => {
setTimeout(callback, 1500);
};
So after 1.5 seconds, it calls the callback function signalizing it is ready for action.
Now lets see how we would make an async hook:
describe('hooks', function() {
let myDB;
before( done => {
myDB = newDB();
myDB(done);
});
//tests
});
And that's it! Hope it helps!

Running Mocha multiple times with the same data produces different results

I have been noticing. With no discernible pattern, that sometimes I run my mocha tests and get a failed assertion. then I run it again immediately. Without making any changes and the assertions all pass. Is there something that I'm doing wrong. Is there test data that is cached?
I, unfortunately don't know what to post, since I can't seem to pin this down to any one thing but here is one function I've seen it happen to
mysqltest.js
describe('get_tablet_station_name', function() {
it ('isSuccessful', function() {
mysqlDao.init();
var callback = sinon.spy();
mysqlDao.get_tablet_station_name(state.TABLET_NAME, function(err, result) {
assert(err == undefined)
});
});
it ('isUnsuccessful', function() {
mysqlDao.init();
var callback = sinon.spy();
mysqlDao.get_tablet_station_name("'''%\0", function(err, result) {
assert(err != undefined);
});
});
});
When the assertions fail it is
assert(err != undefined);
err is returning null despite the bad SQL statement.
You should share the error you are getting when test case is getting failed.
But from you code and problem described, I can guess that your mysql calls must be taking time greater than the default timeout of mocha test cases. And while running your test case for the second time mysql must be returning data from cache hence preventing timeout.
To debug try increasing the default timeout of your test case, and for that use inside you describe call ->
describe('get_tablet_station_name', function() {
this.timeout(10000);
......//rest of the code
Please note this could not be the solution,please provide why assertion is getting failed if above mentioned thing do not work.

How to test error in request with Nock?

I want to test the error in a request return. I'm using nock in my tests, how can I force Nock to provoke an error? I want to achieve 100% test coverage and need to test err branch for that
request('/foo', function(err, res) {
if(err) console.log('boom!');
});
Never enter in the if err branch. Even if hit err is a valid response, my Nock line in test looks like this
nock('http://localhost:3000').get('/foo').reply(400);
edit:
thanks to some comments:
I'm trying to mock an error in the request. From node manual:
https://nodejs.org/api/http.html#http_http_request_options_callback
If any error is encountered during the request (be that with DNS resolution, TCP level errors, or actual HTTP parse errors) an 'error' event is emitted on the returned request object
An error code (e.g. 4xx) doesn't define the err variable. I'm trying to mock exactly that, whatever error that defines the err variable and evaluates to true
Use replyWithError.
From the docs:
nock('http://www.google.com')
.get('/cat-poems')
.replyWithError('something awful happened');
When you initialise a http(s) request with request(url, callback), it returns an event emitter instance (along with some custom properties/methods).
As long as you can get your hands on this object (this might require some refactoring or perhaps it might not even be suitable for you) you can make this emitter to emit an error event, thus firing your callback with err being the error you emitted.
The following code snippet demonstrates this.
'use strict';
// Just importing the module
var request = require('request')
// google is now an event emitter that we can emit from!
, google = request('http://google.com', function (err, res) {
console.log(err) // Guess what this will be...?
})
// In the next tick, make the emitter emit an error event
// which will trigger the above callback with err being
// our Error object.
process.nextTick(function () {
google.emit('error', new Error('test'))
})
EDIT
The problem with this approach is that it, in most situations, requires a bit of refactoring. An alternative approach exploits the fact that Node's native modules are cached and reused across the whole application, thus we can modify the http module and Request will see our modifications. The trick is in monkey-patching the http.request() method and injecting our own bit of logic into it.
The following code snippet demonstrates this.
'use strict';
// Just importing the module
var request = require('request')
, http = require('http')
, httpRequest = http.request
// Monkey-patch the http.request method with
// our implementation
http.request = function (opts, cb) {
console.log('ping');
// Call the original implementation of http.request()
var req = httpRequest(opts, cb)
// In next tick, simulate an error in the http module
process.nextTick(function () {
req.emit('error', new Error('you shall not pass!'))
// Prevent Request from waiting for
// this request to finish
req.removeAllListeners('response')
// Properly close the current request
req.end()
})
// We must return this value to keep it
// consistent with original implementation
return req
}
request('http://google.com', function (err) {
console.log(err) // Guess what this will be...?
})
I suspect that Nock does something similar (replacing methods on the http module) so I recommend that you apply this monkey-patch after you have required (and perhaps also configured?) Nock.
Note that it will be your task to make sure you emit the error only when the correct URL is requested (inspecting the opts object) and to restore the original http.request() implementation so that future tests are not affected by your changes.
Posting an updated answer for using nock with request-promise.
Let's assume that your code calls request-promise like this:
require('request-promise')
.get({
url: 'https://google.com/'
})
.catch(res => {
console.error(res);
});
you can set up nock like this to simulate a 500 error:
nock('https://google.com')
.get('/')
.reply(500, 'FAILED!');
Your catch block would log a StatusCodeError object:
{
name: 'StatusCodeError',
statusCode: 500,
message: '500 - "FAILED!"',
error: 'FAILED!',
options: {...},
response: {
body: 'FAILED!',
...
}
}
Your test can then validate that error object.
Looks like you're looking for an exception on a nock request, this maybe can help you:
var nock = require('nock');
var google = nock('http://google.com')
.get('/')
.reply(200, 'Hello from Google!');
try{
google.done();
}
catch (e) {
console.log('boom! -> ' + e); // pass exception object to error handler
}

Using a domain to test for an error thrown deep in the call stack in node.

I'm trying to write some tests that catch errors that are potentially thrown deep in a nest of callbacks and I decided to try using domains for this. I've managed to simplify to the following test case:
"use strict";
var assert = require("assert");
var domain = require("domain");
function wrapInDomain(throwsAnError, callback) {
var thisDomain = domain.create();
thisDomain.on("error", function(error) {
console.log("calling callback");
//thisDomain.destory(); // I'm not sure if I should do this
callback(error);
});
thisDomain.run(function() {
process.nextTick(function(){
throwsAnError();
});
});
}
function throwsAnError() {
process.nextTick(function(){
throw new Error("I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.");
});
}
describe("describe something that throws an error", function(){
it("it clause", function(done) {
wrapInDomain(throwsAnError, function(theError) {
console.log("got an error " + theError);
assert(false); //Assert something
done();
});
});
});
If the assert passes mocha gives the nice colourful summary of how many tests passed or failed. But if an assert fails, node seems to crash and drops directly. The error listed is the original rather than the failed assert.
Am I doing something very wrong here? Or is this some kind of bug that needs reporting?
calling callback
got an error Error: I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.
/home/gareth2/cloud/apifacade/src/test/resources/testCase.js:23
throw new Error("I sensed a great disturbance in the force, as if mill
^
Error: I sensed a great disturbance in the force, as if millions of voices cried out in terror and were suddenly silenced. I fear something terrible has happened.
at /home/gareth2/cloud/apifacade/src/test/resources/testCase.js:23:15
at process._tickDomainCallback (node.js:463:13)
*node crashes*
I'm using the following version of node.
$ node --version
v0.10.33
The problem is that you need to exit the domain before Mocha can trap the failing exception, because event handlers that are bound to a domain execute in the domain. If you change your error handler to this, it will work:
thisDomain.on("error", function(error) {
thisDomain.exit();
process.nextTick(function () {
callback(error);
console.log("calling callback");
});
});
You need to call process.nextTick (or setImmediate or setTimeout(..., 0)) in the code above so that the statement callback(error) executes in the domain that becomes effective after thisDomain.exit() runs. The way Node works, when you create a new callback for handling an event or to run with process.nextTick (or equivalent functions), then the callback as a whole is associated with a specific domain. Suppose the following callback
myDomain.on("error", function () {
A;
myDomain.exit();
B;
});
Any error caused by A will be handled in myDomain, but the same is true of B because B belongs to the same callback as A.
By using process.nextTick, we create a new callback which is associated with the new domain that takes effect after thisDomain.exit() executes. Modifying the example above, it would be:
myDomain.on("error", function () {
A;
myDomain.exit();
process.nextTick(function () {
B;
});
});
Now B belongs to a different callback from A and this callback was created after we exited myDomain so it executes in the domain that was in effect before myDomain was created.

Mocha tests timeout if more than 4 tests are run at once

I've got a node.js + express web server that I'm testing with Mocha. I start the web server within the test harness, and also connect to a mongodb to look for output:
describe("Api", function() {
before(function(done) {
// start server using function exported from another js file
// connect to mongo db
});
after(function(done) {
// shut down server
// close mongo connection
});
beforeEach(function(done) {
// empty mongo collection
});
describe("Events", function() {
it("Test1", ...);
it("Test2", ...);
it("Test3", ...);
it("Test4", ...);
it("Test5", ...);
});
});
If Mocha runs more than 4 tests at a time, it times out:
4 passing (2s)
1 failing
1) Api Test5:
Error: timeout of 2000ms exceeded
at null.<anonymous> (C:\Users\<username>\AppData\Roaming\npm\node_modules\moch\lib\runnable.js:165:14)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If I skip any one of the 5 tests, it passes successfully. The same problem occurs if I reorder the tests (it's always the last one that times out). Splitting the tests into groups also doesn't change things.
From poking at it, the request for the final test is being sent to the web server (using http module), but it's not being received by express. Some of the tests make one request, some more than one. It doesn't affect the outcome which ones I skip. I haven't been able to replicate this behaviour outside mocha.
What on earth is going on?
With Mocha, if you declare a first argument to your (test) functions' callback (usually called done), you must call it, otherwise Mocha will wait until it's called (and eventually time out). If you're not going to need it in a test, don't declare it:
it('test1', function(done) {
..
// 'done' declared, so call it (eventually, usually when some async action is done)
done();
});
it('test2', function() {
// not an async test, not declaring 'done', obviously no need to call it
});
And since you're using http, try increasing http.globalAgent.maxSockets (which defaults to 5):
var http = require('http');
http.globalAgent.maxSockets = 100;
(I believe 0 turns it off completely but I haven't tried).

Resources