I am trying to prototype a load testing scenario on socket interactions using Mocha and should.js. I have an array of user details which I want to authenticate using socket communication and wish to verify their responses. It works fine for a single user, however when I try to loop for multiple users - I end up with issues. Had gathered some inputs based on the post:Tests from looping through async JavaScript (Mocha) .
Below is the code snippet:
var users = [{name:'A',password:'password',expected:'success'},{name:'B',password:'badPass',expected:'failure'}];
describe('socket Interaction test' , function() {
function socketInteraction(users, done) {
client.emit('userAuthentication', {'name':users.name,'password':users.password}, function(callback) {
console.log('Emit' + users.name);
});
client.on('userAuthenticationResponse', function(response) {
console.log('Resp' + response.status + 'Expected' + users.expected);
response.status.should.equal(users.expected);
done();
});
}
it('Dummy', function(done) {
describe('Mutiple login Test Async', function() {
it('User Login Test', function(done) {
users.forEach(function(users, callback) {
console.log(users.name);
socketInteraction(users, function(err) {
if (err) {
return;
}
done();
});
});
});
});
});
});
The response I get upon running the test is:
socket Interaction test
✓ Dummy
Mutiple login Test Async
A
B
RespsuccessExpectedsuccess
✓ User Login Test
RespsuccessExpectedfailure
2 passing (43ms)
The second test has to fail. Not sure where I have messed up the code. Appreciate some pointers to fix this. Thanks.
The done Parma should be called in the second param of the async.forEach. The done you call in the loop function should be callback(), to tell async that just that user is finished.
You don't have the async finished callback yet at all.
Would have posted code but am on my phone. I can add later if it's not clear.
Related
I have a function which resolves by taking a callback like function(error, result) { ... } as a parameter. I'm trying to use mocha to test this function, but the problem is that the function returns asynchronously, so there's no good place for me to put the done(). If I put inside my result handler, it takes too long and mocha times out. If I put it outside, the test always passes because the handler hasn't been called yet. Here is my code. What's the best way to get around this?
lbl.createLabels is a function that takes an array of customers, and a directory, and creates a bunch of files in that directory, and then asynchronously calls the callback of type: function(error, callback).
describe('Tests', () => {
it('returns a list of customer objects', (done) => {
lbl.createLabels(customers, __dirname + "/..", (err, result) => {
err.should.equal(undefined)
result.should.be.a('array')
result[0].should.have.property('id')
result[0].should.have.property('tracking')
result[0].should.have.property('pdfPath')
const a = {prop:3}
a.prop.should.be.an('array')
done() // putting done() here results in a timeout
})
done() // putting done here results in the test exiting before the callback gets called
})
})
Mocha's documentation has an entire section describing how to test asynchronous code:
https://mochajs.org/#asynchronous-code
Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named done) to it(), Mocha will know that it should wait for this function to be called to complete the test.
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) done(err);
else done();
});
});
});
});
I have some mocha tests I run with Nodejs to test a web server.
Many of the tests should cause the server to return an error, e.g. 400 Bad Request.
Currently the tests are peppered with many copies of the following code:
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
Here's a simplified pseudocode example:
describe('When passing bad JSON data', function(){
var response
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
response = resp
done()
}
}
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST)
})
}
This bugs me because as a programmer I avoid duplicate code wherever possible.
However, putting this into a function does not work:
function verifyItReturnedBadRequest400(httpResponse)
{
it('should respond with 400 (Bad Request)', function (){
expect(httpResponse.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
}
because the call to it() doesn't test the assertion right then; my [limited] understanding is that it() adds the closure to the list of tests. So by the time that check is done, the httpResponse variable has gone out of scope. (I don't understand why that is the case, because in both cases there is a call to it(); why would it matter that in one case it's inside another level of function call? I'm probably missing something with regard to Javascript scoping.)
Is there a common way to avoid all this duplicate code? Or is everyone out there duplicating all their assertion code everywhere? This is my first foray into Mocha so I am probably missing something obvious.
Also, bonus points for explaining why doesn't the function approach work?
Thanks!
There is an article on wiki about this.
https://github.com/mochajs/mocha/wiki/Shared-Behaviours
I guess you have some bugs in your test. Placing it() into wrapper function works fine. Here's a small working demo.
'use strict';
const assert = require('assert');
const xEqualsOne = () => {
it('should be equal 1', () => {
assert.equal(this.x, 1);
});
};
describe('async number', () => {
this.x = 0;
before(done => {
this.x++
setTimeout(done, 100);
});
xEqualsOne();
});
I guess your code looks something like this:
describe('When passing bad JSON data', function(){
var response
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
response = resp
done()
}
}
verifyItReturnedBadRequest400(httpResponse)
}
Think about it like this:
it() creates a test.
All the calls to it happen before any tests are actually run (you have to create tests before you run them)
The function passed to `before' is run after the tests have been created, but before they are run.
verifyItReturnedBadRequest400 calls it, to create a test, but you're passing in httpResponse right then before any tests have run, so before hasn't run yet either.
You could continue to use that sort of pattern, but you'll need to put the httpresponse in a container so you can pass a reference to it:
describe('When passing bad JSON data', function(){
var data = {};
before(function(done){
callUrlToInsert(url, badJson, function(err, resp){
data.response = resp
done()
}
}
verifyItReturnedBadRequest400(data)
}
and then your verifyItReturnedBadRequest400 becomes:
function verifyItReturnedBadRequest400(data) {
it('should respond with 400 (Bad Request)', function (){
expect(data.response.statusCode).to.equal(httpstatus.BAD_REQUEST);
});
}
I am still learning node.js basics. My flow is like this,
browser<-->node<-->backend server doing calculation.
node and backend uses socket to communicate.
From the browser there are start/stop buttons to ask backend to start/stop the
calculation.
When node asks backend to start/stop, it must query to see if backend is
alive first.
My code is like this -
app.get('/stopCmd', function(req, res)
{
socketToBackendServer.write("status", function() {
console.log("Sending:", 'Node asking for STATUS');
});
socketToBackendServer.on("data", function() {
if(status is ok) // pseudo code
{
socketToBackendServer.write("stop", function() {
console.log("Sending:", 'Node sending STOP');
});
} else {
console.log("backend server is NOT ready");
}
});
});
app.get('/startCmd', function(req, res)
{
// do similar things as stopCmd
});
/////////////////////////////////////////////////
var socketToBackendServer = net.connect(2899);
function openSocket() {
socketToBackendServer.setKeepAlive(true);
socketToBackendServer.on('connect', onConnect.bind({}, socketToBackendServer));
socketToBackendServer.on('error', onError.bind({}, socketToBackendServer));
}
function onConnect(socket) {
var myData;
console.log('Socket is open!');
socket.on('data', function(data) {
console.log('Received:', data);
io.emit('time', { time: data.toJSON() });
});
}
function onError(socket) {
console.log('Socket error!');
// Kill socket
clearInterval(interval);
socket.destroy();
socket.unref();
// Re-open socket
setTimeout(openSocket, 1e3);
}
openSocket();
server.listen(7778);
if using the same browser, if i go crazy clicking start/stop... for the "
stopCmd", how to make sure when it queries "status", the response is caught
by its function, not "startCmd"'s ?
it's this line
socketToBackendServer.on("data", function()
Thank you again !
You can use multiple connections to the backend server, so one function can freely use one channel, the responses won't mix.
Or you can use a multiplexer function, that you call from both of your functions:
It could work if you can identify your requests, like you send and id with the status, for example socketToBackendServer.write("status 1", ... , and you send the id with the status response back from the backend server (if it yours). In this way you can send multiple requests at the same time, and when the response come, you can identify it, and call the callback function that you stored in an array with the ids.
You only send one request, and you wait for the response before you send another one. You must use a waiting queue, where you store the request, and the callback functions.
I'm trying to write tests for my npm module, which takes care of communicating with my backend api. this module will sit inside a cordova android app, and will take care of any api calls. the issue that i'm having seems to be an understanding of mocha, but i've had a good look around the internet and can't find a solution so i turn to the masses. As an example, i have a function like
test: function() {
request.get({
url: defaultHost,
headers: {
}
}, function(err, httpResponse, body) {
if(err) {
return err;
} else {
console.log(body);
return body;
}
});
}
this works will. i'm now trying to create the test for it in mocha. the problem that i'm getting is that i have no idea how to get the return function from the .get call into the mocha test. the api returns json, so i know that i'm going to have to be doing an is equal comparison, but at the moment i can't even get it to print the results. i think the problem with is that with my other mocha tests that i can get working, they all have an argument that you pass in where as this doesn't. my current code for the test looks like this.
describe('#test', function() {
it('tests api reachability;', function() {
var test = new test();
});
});
if someone can explain what is required afterwards or even just point me in the right direction on google, that would be awesome. i'm normally pretty good at the google, but failing to find direction on this one.
I think nock will solve this issue. Let's assume you sending get request to some resource (http://domain.com/resource.json) and the tests would be like this:
var nock = require('nock');
// ...
describe('#test', function() {
beforeEach(function () {
nock('http://domain.com')
.get('resource.json')
.reply(200, {
message: 'some message'
});
});
it('tests api reachability;', function() {
var test = new test();
});
});
In my node application I'm using mocha to test my code. While calling many asynchronous functions using mocha, I'm getting timeout error (Error: timeout of 2000ms exceeded.). How can I resolve this?
var module = require('../lib/myModule');
var should = require('chai').should();
describe('Testing Module', function() {
it('Save Data', function(done) {
this.timeout(15000);
var data = {
a: 'aa',
b: 'bb'
};
module.save(data, function(err, res) {
should.not.exist(err);
done();
});
});
it('Get Data By Id', function(done) {
var id = "28ca9";
module.get(id, function(err, res) {
console.log(res);
should.not.exist(err);
done();
});
});
});
You can either set the timeout when running your test:
mocha --timeout 15000
Or you can set the timeout for each suite or each test programmatically:
describe('...', function(){
this.timeout(15000);
it('...', function(done){
this.timeout(15000);
setTimeout(done, 15000);
});
});
For more info see the docs.
I find that the "solution" of just increasing the timeouts obscures what's really going on here, which is either
Your code and/or network calls are way too slow (should be sub 100 ms for a good user experience)
The assertions (tests) are failing and something is swallowing the errors before Mocha is able to act on them.
You usually encounter #2 when Mocha doesn't receive assertion errors from a callback. This is caused by some other code swallowing the exception further up the stack. The right way of dealing with this is to fix the code and not swallow the error.
When external code swallows your errors
In case it's a library function that you are unable to modify, you need to catch the assertion error and pass it onto Mocha yourself. You do this by wrapping your assertion callback in a try/catch block and pass any exceptions to the done handler.
it('should not fail', function (done) { // Pass reference here!
i_swallow_errors(function (err, result) {
try { // boilerplate to be able to get the assert failures
assert.ok(true);
assert.equal(result, 'bar');
done();
} catch (error) {
done(error);
}
});
});
This boilerplate can of course be extracted into some utility function to make the test a little more pleasing to the eye:
it('should not fail', function (done) { // Pass reference here!
i_swallow_errors(handleError(done, function (err, result) {
assert.equal(result, 'bar');
}));
});
// reusable boilerplate to be able to get the assert failures
function handleError(done, fn) {
try {
fn();
done();
} catch (error) {
done(error);
}
}
Speeding up network tests
Other than that I suggest you pick up the advice on starting to use test stubs for network calls to make tests pass without having to rely on a functioning network. Using Mocha, Chai and Sinon the tests might look something like this
describe('api tests normally involving network calls', function() {
beforeEach: function () {
this.xhr = sinon.useFakeXMLHttpRequest();
var requests = this.requests = [];
this.xhr.onCreate = function (xhr) {
requests.push(xhr);
};
},
afterEach: function () {
this.xhr.restore();
}
it("should fetch comments from server", function () {
var callback = sinon.spy();
myLib.getCommentsFor("/some/article", callback);
assertEquals(1, this.requests.length);
this.requests[0].respond(200, { "Content-Type": "application/json" },
'[{ "id": 12, "comment": "Hey there" }]');
expect(callback.calledWith([{ id: 12, comment: "Hey there" }])).to.be.true;
});
});
See Sinon's nise docs for more info.
If you are using arrow functions:
it('should do something', async () => {
// do your testing
}).timeout(15000)
A little late but someone can use this in future...You can increase your test timeout by updating scripts in your package.json with the following:
"scripts": {
"test": "test --timeout 10000" //Adjust to a value you need
}
Run your tests using the command test
For me the problem was actually the describe function,
which when provided an arrow function, causes mocha to miss the
timeout, and behave not consistently. (Using ES6)
since no promise was rejected I was getting this error all the time for different tests that were failing inside the describe block
so this how it looks when not working properly:
describe('test', () => {
assert(...)
})
and this works using the anonymous function
describe('test', function() {
assert(...)
})
Hope it helps someone, my configuration for the above:
(nodejs: 8.4.0, npm: 5.3.0, mocha: 3.3.0)
My issue was not sending the response back, so it was hanging. If you are using express make sure that res.send(data), res.json(data) or whatever the api method you wanna use is executed for the route you are testing.
Make sure to resolve/reject the promises used in the test cases, be it spies or stubs make sure they resolve/reject.