Mocha&Chai: Writing assertion - node.js

I am writing test cases using mocha and chai for the first time. This is a very simple response returned by my service:
{
"success": true,
"message": "Done"
}
I have written assertion like this:
describe('GET /TestService', function() {
it('should run successfully.', function(done) {
request
.get('/myApp/TestService/')
.expect(200)
.expect('Content-Type', 'application/json')
.end(function(err, res) {
expect(res.body.success).to.equal(true);
expect(res.body.message).to.equal('Done');
});
});
});
When I execute the test it returns:
Uncaught AssertionError: expected undefined to equal true
What is wrong with this? This is my first ever encounter with Mocha and Chai. Maybe I am missing a very basic thing. This is just the first step. Can someone push me forward?

Related

what is the difference between .done() and .end() function in node and when they shall be used?

I am trying to understand the use case of end() function while writing the API test script in mocha and Chai. Also at the same time, I am confused about whether I shall use the done() function here or not and also what is the exact difference between .end() and .done().
Here's the code:
describe("Suite", () => {
it('Post Test case', (done) => {
request('https://reqres.in')
.post('/api/users')
.send({
"name": "morpheus",
"job": "leader"
})
.set('Accept', 'application/json')
.expect(200,'Content-Type', /json/)
.then((err,res) => {
console.log(JSON.stringify(err))
console.log(JSON.stringify(res.body))
console.log(JSON.stringify(" "))
})
done();
});
it('Put Test case', (done) => {
request('https://reqres.in')
.put('/api/users/2')
.send({
"name": "morpheus",
"job": "zion residents"
})
.expect(200)
.end((err, res) => {
console.log(JSON.stringify(err))
console.log(JSON.stringify(res.body))
console.log(JSON.stringify(" "))
})
done();
})
})
You are mixings things a little bit.
end is a method of the expressjs framework and it ends the server response.
done is a parameter of mocha test function. You call this parameter when you are finished with your asynchronous test to let the mocha know that your asynchronous code is done executing, and it can move on to another test.
And in your case, you need them both.

Is it possible to add information to the error message in supertest

I'm utilizing supertest with mocha to test a nodejs express app. Everything is fine expect I'd like a little more descriptive error messages. That's not to say the messages are currently bad, they're not. I'd just like a little more information.
For example:
it('should successfully post my data and return a valid JSON', function(done) {
.post(url)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.send(data)
.expect(201, resultBody)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
If an error should occur, such that the resultBody doesn't match the actual result, it'll print out a nice + expected - actual message. But I would also like to see other information (maybe the authentication or the header).
My current solution is to do the following:
.end(function(err, res) {
if (err) {
console.log(res.headers);
console.log(res.statusCode);
console.log(res.body);
return done(err);
}
done();
});
But the console.log messages appear inline with the "it" messages, before the passing/pending/failing messages and not with the actual error.
Is it possible, without too much extra effort, to put extra information with the error message?
You can fix it using the Language Chains of Chai in expect and should adding Assertion Styles:
var foo = false;
expect(foo, 'foo must be true').to.be.true;
//AssertionError: foo must be true: expected false to be true

Keeping client state when an api with mocha

My api can be asked to create an object, then later asked to update that same object, so my test file does this...
var foobarId; // this might be a mistake
it("should create a single foobar", function(done) {
server
.post("/foobar?key=value")
.expect("Content-type", /json/)
.expect(200)
.end(function(err, res) {
res.status.should.equal(200);
res.body.should.have.property('key', 'value');
foobarId = res.body._id;
done();
});
});
it("should return a foobar when I get one", function(done) {
server
.get("/foobar/" + foobarId)
.expect("Content-type", /json/)
.expect(200)
.end(function(err, res) {
res.status.should.equal(200);
res.body.should.have.property('key', 'value');
done();
});
});
So is this wrong what I'm trying here? (1) as I get more logic into the test, I risk creating logic errors in the test and needing a test for my test. (2) when the create fails, my console output gets ugly... first, the assertion error that I expect and need telling me the test failed, but then ugly traceback stuff, I think, because foobarId is undefined.
The ugliness makes me think that the good people at mocha (or supertest or wherever) didn't expect me to do what I'm doing.
Is there a right way to write this kind of test?

supertest .expect(function(res) {}) what to return if test is ok

if have a test made with mocha and supertest:
describe('GET /v1/news/5339a146d46d35ebe953030a --test', function(){
it('respond with json', function(done){
request(app)
.get('/v1/news/5339a146d46d35ebe953030a')
.set('Accept', 'application/*')
.set('DEV-ROLE', 'test')
.expect('Content-Type', /json/)
.send(json)
.expect(200)
.expect(function(res) {
//THIS FUNCTION RESULT IN A TIMEOUT IF NO ERROR IS THROWN
if(!('item' in res.body)) throw new Error("missing item key");
})
.end(function(err, res){
if (err) return done(err);
done()
});
})
})
i want to test the resulting body, but i always run in a timeout.
if an error occures, i can throw an error, thats fine. But if no error occures, i run into a timeout if I retourn nothing like discribed in the documentation:
Pass a custom assertion function. It'll be given the response object
to check. If the response is ok, it should return falsy, most commonly
by not returning anything. If the check fails, throw an error or
return a truthy value like a string that'll be turned into an error
Example im docu:
request(app)
.get('/')
.expect(hasPreviousAndNextKeys)
.end(done);
function hasPreviousAndNextKeys(res) {
if (!('next' in res.body)) return "missing next key";
if (!('prev' in res.body)) throw new Error("missing prev key");
}
I use version 0.12.1
Waiting for Version 0.13.0 solved the issue. Now it works.

In mocha testing while calling asynchronous function how to avoid the timeout Error: timeout of 2000ms exceeded

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.

Resources