Mocha: 'Timeout of 2000ms exceeded' issue with Mocha and Mongoose

Created on 11 Aug 2015  Â·  9Comments  Â·  Source: mochajs/mocha

Here is my mocha testing file test-api.js :

var should = require('should');
var mongoose = require('mongoose');
var request = require('supertest');
var db = require('../config/db');
var post = require('../app/models/post');
var faker = require('faker');


describe('Post', function () {
    var url = 'http://localhost:3000';

    before(function (done) {
        var db_url = db.url_test;
        mongoose.connect(db_url, done);
    });

    it('should post a post and get the post back', function (done) {
        var _body = {
            title: faker.name.title(),
            body: faker.lorem.paragraph()
        };
        //console.log(_body);
        request(url)
            .post('/api/post')
            .send(_body)
            .end(function (err, res) {
                //if (err) {
                //    console.log(err);
                //    //console.log('/api/post post method failed!');
                //}
                //console.log('res.body: ');
                //console.log(res.body);
                res.body.should.have.property('url');
                res.body.should.have.property('title');
                res.body.should.have.property('body');
                res.body.should.have.property('date');
                done();
            });
    });

    it('should get all the posts', function (done) {
        request(url)
            .get('/api/post')
            .expect(200)
            .end(function (err, res) {
                if (err) {
                    console.log(err);
                    //console.log('/api/post get method failed!')
                }
                res.body.should.have.property('count');
                res.body.should.have.property('limit');
                res.body.should.have.property('page');
                res.body.should.have.property('results');
                //console.log(res.body);
                done();
            });
    });
});

I think the problem is inside the before function, because if I run mongoose.connect() inside the server.js (Which is the api launching js file), I can get the test passing output.

But I want to use the specific database only for testing, so I don't want to put the mongoose.connect() inside the server.js file.

Here is the problematic output of mocha:

    1) should post a post and get the post back
    ✓ should get all the posts (52ms)


  1 passing (2s)
  1 failing

  1) Post should post a post and get the post back:
     Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

Now I have no idea how to deal with this problem, please help me (T_T).... Thank you.!

Most helpful comment

I just discovered a much cleaner work around. Use promises:

var mongoose = require('mongoose'),
    mockgoose = require('mockgoose'),
    should = require('should-promised'),
    User;

before(function() {
    mockgoose(mongoose);
    mongoose.connect('mongodb://localhost/mydatabase');
    User = require('./../../models/user-model');
});

after(function() {
    mockgoose.reset();
    mongoose.connection.close();
});

describe('given a valid user', function() {
    it('should create an user', function() {
        return User.create({
            foo: 'bar'
        }).should.eventually.have.property('foo', 'bar');
    });
});

All 9 comments

Have you tried adding a timeout to request? https://github.com/request/request#requestoptions-callback

timeout - Integer containing the number of milliseconds to wait for a server to send response headers
 (and start the response body) before aborting the request. Note that if the underlying TCP connection
 cannot be established, the OS-wide TCP connection timeout will overrule the timeout option
(the default in Linux can be anywhere from 20-120 seconds).

You should set a longer timeout in the tests which need it:

it('should post a post and get the post back', function (done) {
  this.timeout(5000);
  // the rest

Closing as OP hasn't replied in a month.

I'm having a similar issue. I tried the timeout and it didn't help. It isn't that the mongoose call takes long, I believe it has something to do with the object that is passed into the mongoose create callback. If I create an instance of the model and call it's save function and reference that instance from within the callback (instead of the one passed into the callback), it appears to work. It is also worth mentioning that it only times out when the test fails.

before(function(done) {
    mockgoose(mongoose);
    mongoose.connect('mongodb://localhost/mydatabase');
    User = require('./../../models/user-model');
    done();
});

describe('given a valid user', function() {
    it('should create a user', function(done) {
        var user = new User({
            foo: 'bar'
        });
        user.save(function(err, u) {
            user.should.have.property('foo', 'notbar');
            // uncommenting the next line will cause timeout
            // u.should.have.property('foo', 'notbar');
            done();
        });
    });
});

I just discovered a much cleaner work around. Use promises:

var mongoose = require('mongoose'),
    mockgoose = require('mockgoose'),
    should = require('should-promised'),
    User;

before(function() {
    mockgoose(mongoose);
    mongoose.connect('mongodb://localhost/mydatabase');
    User = require('./../../models/user-model');
});

after(function() {
    mockgoose.reset();
    mongoose.connection.close();
});

describe('given a valid user', function() {
    it('should create an user', function() {
        return User.create({
            foo: 'bar'
        }).should.eventually.have.property('foo', 'bar');
    });
});

Model.save (err, instance) ->
    mongoose.disconnect()
    if !err true else false

works for me.

And my HTTP unit test (doing supertest as request, and not loading models from Schema) has:

after (done) ->
    mongoose.disconnect()
    done()
    return

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

I my case, I read through the source code and found out that mongodb-prebuild need to download the mongodb binary on first run. I did not realize that there is a download progress when running it manually through terminal (I was using WebStorm's GUI). I'd appreciate it if this is mentioned in README.md. I guess that is the reason for changing the timeout to two minutes, which IMHO is not a very good advice. I'm sure there is a good reason that the default timeout is two second. And two minutes is not enough for me to download the (approximately 98 MB binary) because of my bad connection.

As a side note, if the download fails (because of bad connection, like mine), it would hang. There seems to be some uncaught promise rejection in mongodb-prebuilt.

We notice that
npm cache verify
fix the issue, but not for a long.
That's why is good idea to run this in cron or in similar task manager.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ibc picture ibc  Â·  59Comments

haraldrudell picture haraldrudell  Â·  52Comments

boneskull picture boneskull  Â·  76Comments

keithamus picture keithamus  Â·  37Comments

teckays picture teckays  Â·  84Comments