Neeraj Sewani
Neeraj Sewani

Reputation: 4287

Getting timeout exceeded error while using Mocha

While testing with Mocha I am getting the following error on running server.test.js

1) "before each" hook for "should get all todos":
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

server.test.js

const expect = require('expect');
const request =  require('supertest');

const {app} = require('./../server');
const {Todo} = require('./../todos');


const todos = [
{
    text: 'This is text 1'
},
{
    text: 'This is text 2'
}
];


beforeEach((done) => {

Todo.remove({}).then(() => {
    return Todo.insertMany(todos);
}).then(() => done());
});


describe('GET /todos', () => {
it('should get all todos', (done) => {

    request(app)
        .get('/todos')
        .expect(200)
        .expect(res => {
            expect(res.body.length).toBe(2);
        })
        .end(done);
});
});

But if I do some changes in beforeEach() method like:

updated server.test.js

const expect = require('expect');
const request =  require('supertest');

const {app} = require('./../server');
const {Todo} = require('./../todos');


const todos = [
{
    text: 'This is text 1'
},
{
    text: 'This is text 2'
}
];

beforeEach((done) => {

Todo.remove({}).then(() => {
    Todo.insertMany(todos);
    done();
})
});


describe('GET /todos', () => {
it('should get all todos', (done) => {

    request(app)
        .get('/todos')
        .expect(200)
        .expect(
            expect(res.body.length).toBe(2);
        })
        .end(done);
});
});

Then I am getting no errors. Basically, by chaining promises in beforeEach() method I am running into an error but without that everything is fine. Could anyone explain why is it happening?

server.js

var express = require('express');
var body_parser = require('body-parser');

const {mongoose} = require('./mongoose.js');
const {Todo} = require('./todos');
const {Todo_1} = require('./todos');

var app = express();

app.use(body_parser.json());



//  using GET method
app.get('/todos', (req, res) => {
Todo.find().then((todos) => {
    res.send(todos);
}, (err) => {
    res.status(400).send(err);
});
});

module.exports = {app}

app.listen(3000, () => {
console.log('Server is up on the port 3000');

})

Upvotes: 3

Views: 893

Answers (2)

b1programmer
b1programmer

Reputation: 187

instead of putting localhost in the url like this: "mongodb://localhost:27017/yourDbName"

use 127.0.0.1, so it becomes like the following:

"mongodb://127.0.0.1:27017/yourDbName"

I do not know what is the reason behind this solution, but it seems that the server needs some time to process and figure out what the IP of the localhost is.

Hopefully this solution solves your issue.

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222319

This is incorrect way to handle promises:

Todo.remove({}).then(() => {
    Todo.insertMany(todos);
    done();
})
});

Todo.insertMany is likely asynchronous and returns a promise, and it's detached from promise chain. If there are errors, they will result in unhandled promise rejections, and since tests depend on inserted rows, this will result in race condition:

Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

means exactly what it says. done either wasn't called, or there was a timeout. It is possible for done to never be called because errors aren't handled. It should be .then(done, done).

Since Mocha supports promises, a proper way is:

beforeEach(() => 
  Todo.remove({})
  .then(() => Todo.insertMany(todos))
);

Every promise that appears somewhere in promise chain should be returned.

Upvotes: 1

Related Questions