Mocha - Which runs first, beforeEach or before? - node.js

I have a web app with a spec like this:
describe('Hook them up', () => {
var server;
beforeEach(done => {
server = app.listen(done);
});
before(done => {
// Does this run before or after "beforeEach"
// If I try to access the api at this point I get an ECONNREFUSED
});
after(done => {
server.close(done);
});
it('should set the \'createdAt\' property for \'DndUsers\' objects', done => {
api.post('/api/tweets')
.send({ text: 'Hello World' })
.then(done)
.catch(err => {
console.log(err);
done();
});
});
});
In some other project of mine, if I try to access the api in the before block it works fine, as if the beforeEach was already run.

See my answer here to a very similar question.
Mocha's test runner explains this functionality the best in the Hooks section of the Mocha Test Runner.
From the Hooks section:
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
});
// test cases
it(...); // Test 1
it(...); // Test 2
});
You can nest these routines within other describe blocks which can also have before/beforeEach routines.
This should give you
hooks
before
beforeEach
Test 1
afterEach
beforeEach
Test 2
afterEach
after

Related

Running multiple mocha files and suites with same context

I'm trying to run several integration tests with some shared context. The context being shared is a single express application, and I'm trying to share it across suites / files because it takes a few seconds to spin up.
I got it to work by instantiating a "runner" mocha test suite, that would have test functions that would just require each test file as needed, and this was working well (a side effect is that the test requiring the child test file would finish as "success" before any of the tests inside the file would actually run, but this was a minor issue)
// test-runner.js:
describe('Integration tests', function () {
let app
let log
this.timeout(300000) // 5 mins
before(function (done) {
app = require('../app')
app.initialize()
.then(() => {
done()
})
.catch(err => {
log.error(err)
done(err)
})
})
it('Running api tests...', (done) => {
require('./integration/api.test')(app)
done()
})
// ./integration/api.test.js:
module.exports = (app) => {
let api = supertest.agent(app)
.set('Content-Type', 'application/json')
describe('Authorization', () => {
describe('Trying to access authorization sections', () => {
it('should be denied for /home', async () => {
await api.get(`${baseUrl}/home`)
.expect(STATUS_CODE.UNAUTHORIZED)
})
...
The Problem:
I want to signal the test runner that all of the tests in the imported suite have finished, so I can call shutdown logic in the test runner and end the test cleanly. In standard test functions, you can pass a done function to signal that the code in the test is complete, so I wrapped each of the child tests in a describe block to use the after hook to signal that the whole test module was done:
// test-runner.js:
describe('Integration tests', function () {
let app
let log
this.timeout(300000) // 5 mins
before(function (done) {
app = require('../app')
app.initialize()
.then(() => {
done()
})
.catch(err => {
log.error(err)
done(err)
})
})
it('Running api tests...', (done) => {
require('./integration/api.test')(app, done)
})
// ./integration/api.test.js:
module.exports = (app, done) => {
let api = supertest.agent(app)
.set('Content-Type', 'application/json')
describe('All api tests', () => {
let api
before(() => {
api = supertest.agent(app)
.set('Content-Type', 'application/json')
})
after(() => {
done() // should be calling the done function passed in by test runner
})
describe('Authorization', () => {
describe('Trying to access authorization sections', () => {
it('should be denied for /home', async () => {
await api.get(`${baseUrl}/home`)
.expect(STATUS_CODE.UNAUTHORIZED)
})
...
but when I do this, the test suites just don't run. The default timeout will just expire, and if I set a higher timeout, it just sits there (waiting for the longer timeout). If I hook into a debug session, then the test exits immediately, and the after hook (and before!) never get called.
I'm open to other ideas on how to do this as well, but I haven't found any good solutions that that allow sharing some context between tests, while having them broken into different files.

Testing express with Mocha: a promise-based test will not run by itself?

I have two test files. When only test1.js is present, no tests run, and mocha reports "0 passing" tests. When test1.js and test2.js are present but both depend on a promise, then still no tests run and mocha still reports "0 passing". But when one of the tests is modified to not use a promise, mocha runs both tests and they succeed. What the heck? Here are my files:
index.js:
require('./server').then( function(server) {
server.listen(8080, function() {
console.log("Started server");
});
);
server.js:
var express = require('express');
var server = express();
module.exports = new Promise((function(resolve, reject) {
return resolve(server);
}));
test1.spec.js:
require('./server').then(function(server) {
describe('Test Suite #1', function () {
it('should run test #1', function testSomething(done) {
return done();
});
});
});
test2.spec.js (server.js used as promise, tests do not run):
require('./server').then(function(server) {
describe('Test Suite #2', function () {
it('should run test #2', function testSomethingElse(done) {
return done();
});
});
});
test2.spec.js (server.js not used as promise, both tests run):
var server = require('./server');
describe('Test Suite #2', function () {
it('should run test #2', function testSomethingElse(done) {
return done();
});
});
To run them, I just have nodejs, express, and mocha installed and run:
% mocha "*.spec.*"
I understand I'm not using the server variable in these examples, but of course the real tests need to return a promise because sometimes the server.js is accessing remote systems for config data. I could work around this, but any help in understanding what's happening here would be greatly appreciated!
You need to describe and define all your tests synchronous. Otherwise they aren't recognized by mocha. If you have some async setup to make, use the before or beforeEach functions:
describe('Test Suite #1', function () {
var server;
before(function(done){
require('./server').then(aServer => {
server = aServer;
done();
});
});
it('should run test #1', function testSomething(done) {
return done();
});
});

Mocha runs only one test

I have a sails.js app that I want to test with mocha, in my test folder I have 2 tests, but when I run mocha only one test gets executed.
Test1.js
var request = require('supertest');
describe.only('UserController', function() {
describe('#login()', function() {
it('should redirect to /mypage', function (done) {
done();
});
});
});
Test2.js
describe.only('UsersModel', function() {
describe('#find()', function() {
it('should check find function', function (done) {
done();
});
});
});
I run tests with this command:
./node_modules/.bin/mocha
Output
UserController
#login()
✓ should redirect to /mypage
1 passing (10ms)
Please explain me my mistake.
It is because you are running an exclusive test by using describe.only(). Use describe() instead.
See exclusive tests in the mocha documentation

Mocha beforeEach and afterEach during testing

I have been trying to test my test server using mocha. This is the following code that I use, almost the same as one found in another similar post.
beforeEach(function(done) {
// Setup
console.log('test before function');
ws.on('open', function() {
console.log('worked...');
done();
});
ws.on('close', function() {
console.log('disconnected...');
});
});
afterEach(function(done) {
// Cleanup
if(readyState) {
console.log('disconnecting...');
ws.close();
} else {
// There will not be a connection unless you have done() in beforeEach, socket.on('connect'...)
console.log('no connection to break...');
}
done();
});
describe('WebSocket test', function() {
//assert.equal(response.result, null, 'Successful Authentification');
});
the problem is that when I execute this draft, none of the console.log that is expected to be seen is visible on the command prompt. Can you please explain to me what am I doing wrong?
Georgi is correct that you need an it call to specify a test but you don't need to have a top level describe in your file if you don't want to. You could replace your single describe with a bunch of it calls:
it("first", function () {
// Whatever test.
});
it("second", function () {
// Whatever other test.
});
This works very well if your test suite is small and composed of only one file.
If your test suite is bigger or spread among multiple files, I would very strongly suggest you put your beforeEach and afterEach together with your it inside the describe, unless you are absolutely positive that every single test in the suite needs the work done by beforeEach or afterEach. (I've written multiple test suites with Mocha and I've never had a beforeEach or afterEach that I needed to run for every single test.) Something like:
describe('WebSocket test', function() {
beforeEach(function(done) {
// ...
});
afterEach(function(done) {
// ...
});
it('response should be null', function() {
assert.equal(response.result, null, 'Successful Authentification');
});
});
If you do not put your beforeEach and afterEach inside describe like this, then let's say you have one file to test web sockets and another file to test some database operations. The tests in the file that contains the database operation tests will also have your beforeEach and afterEach executed before and after them. Putting the beforeEach and afterEach inside the describe like shown above will ensure that they are performed only for your web socket tests.
You have no tests in your example. If there are no tests to be run, then before and after hooks won't be invoked. Try adding a test like:
describe('WebSocket test', function() {
it('should run test and invoke hooks', function(done) {
assert.equal(1,1);
done();
});
});
You need to have a test-callback(eg. it) inside suite-callback(eg, describe) to execute beforeEach() and afterEach() hooks. More info https://mochajs.org/#run-cycle-overview

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