3

So I'm working on an express.js app where I have a mongoose model User. I wrote a test file (using Mocha) to test the save() function but all of my tests are taking too long to execute and ultimately timeout.

Here are the errors I'm getting:

  Testing - Server - User - Model
    Testing save()
      1) should be able to save without problems
      2) should fail to save an exisitng user again
      3) should should an error when try to save with empty email
      4) should give an error when try to save with empty password
    5) "after all" hook


  0 passing (8s)
  5 failing

  1) Testing - Server - User - Model Testing save() should be able to save without problems:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  2) Testing - Server - User - Model Testing save() should fail to save an exisitng user again:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  3) Testing - Server - User - Model Testing save() should should an error when try to save with empty email:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

  4) Testing - Server - User - Model Testing save() should give an error when try to save with empty password:
     Uncaught AssertionError: expected null to exist
      at Promise.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/test/models/user.server.model.test.js:69:12)
      at Promise.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
      at Promise.emit (events.js:98:17)
      at Promise.emit (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
      at Promise.fulfill (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
      at handleSave (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/model.js:133:13)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/utils.js:408:16
      at model.save (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/model.js:222:7)
      at model._done (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:59:24)
      at _next (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:52:28)
      at fnWrapper (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:159:8)
      at model.<anonymous> (/Users/Mukul/PersonalProjects/ResourceBucket/models/user.js:22:46)
      at _next (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:50:30)
      at fnWrapper (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/node_modules/hooks/hooks.js:159:8)
      at complete (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:992:5)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:983:20
      at ObjectId.SchemaType.doValidate (/Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/schematype.js:603:22)
      at /Users/Mukul/PersonalProjects/ResourceBucket/node_modules/mongoose/lib/document.js:974:9
      at process._tickCallback (node.js:442:13)

  5) Testing - Server - User - Model "after all" hook:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

Here's my test file:

// Module dependencies
var should = require("should");
var mongoose = require("mongoose");
var config = require('../../config/config');
var nodemailer = require('nodemailer');
var bcrypt = require('bcryptjs');

// Get User model
var User = require('../../models/user')(mongoose, config, bcrypt, nodemailer).User;

// Define global test variables
var user;
var user2;

// Unit tests
describe('Testing - Server - User - Model', function(){

    // Since its before - it happens once ONCE before ALL the tests
    before(function(done){
        // Since we're using the global variables don't use var in front of them
        user = new User({
            email: 'a@a.com',
            password: 'a'
        });

        // Another user with same details as the first user cos
        // For a test case, where we try to insert 2 records with same details (should fail as exprected)
        user2 = new User({
            email: 'a@a.com',
            password: 'a'
        });
        done();
    });

    // Testing function #1 - save()
    describe('Testing save()', function(){

        // Test case #1 - save normally
        it('should be able to save without problems', function(done){
            try { 
                user.save(done);
            } catch (x) { 
                done(x);
            }
        });

        // Test case #2 - should fail to save an exisitng user again
        it('should fail to save an exisitng user again', function(done){
            user.save(function(){
                user2.save(function(err){
                    should.exist(err);
                    done();
                });
            });
        })

        // Test case #3 - should give an error when try to save with empty email
        it('should should an error when try to save with empty email', function(done){
            user.email = '';
            return user.save(function(err){
                should.exist(err);
                done();
            });
        });

        // Test case #4 - should give an error when try to save with empty password
        it('should give an error when try to save with empty password', function(done){
            return user.save(function(err){
                should.exist(err);
                done();
            });
        });
    });

    after(function(done){
        User.remove().exec(done);
    });
});

and here's my User model file:

module.exports = function(mongoose, config, bcrypt, nodemailer){

  // User schema 
  var userSchema = new mongoose.Schema({
    email: {
      type: String,
      unique: true,
      lowercase: true
    },
    password: {
      type: String,
      select: false
    }
  });

  // Makes sure that our passwords are always hashed before saving to the database
  // Refer to sessionBuddy's resources for more info on this 
  userSchema.pre('save', function(next) {
    var user = this;

    // Only hash the password if its modified or new
    if (!user.isModified('password')) return next();

    // Generate salt
    bcrypt.genSalt(config.SALT_WORK_FACTOR, function(err, salt) {
      if (err) return next(err);

      // hash the password along with the salt
      bcrypt.hash(user.password, salt, function(err, hash) {
        if (err) return next(err);

        // overwrite the cleartext password with the hashed one
        user.password = hash;
        next();
      });
    });
  });

  // Password verification for cleartext and hashed passwords
  userSchema.methods.comparePassword = function(password, done) {
    bcrypt.compare(password, this.password, function(err, isMatch) {
      done(err, isMatch);
    });
  };

  var User = mongoose.model('User', userSchema);

  return{
    User : User
  }
}

I also tried the try/catch way for promises from this thread: In mocha testing while calling asynchronous function how to avoid the timeout Error: timeout of 2000ms exceeded. But that didn't work either.

Any help is appreciated! Thanks

EDIT: As suggested in the comments I wasn't connecting to the database in the test file. EDIT2: Getting the following error with the last 2 tests now - "Uncaught AssertionError: expected null to exist" EDIT3: Actually my schema was okay with saving "email" and "password" empty since I wasn't setting the required field true, after updating my schema, it works.

Community
  • 1
  • 1
Mukul Raina
  • 351
  • 1
  • 5
  • 14
  • It looks like you didn't actually connect to the mongodb database. If you don't do that, all your requests will be queued and never be executed. – victorkt Mar 06 '15 at 01:20
  • additionally if you want to still have a testing env without a DB set up you can use `rewire` to redefine `User#save` – Mauricio Poppe Mar 06 '15 at 01:35
  • yep sorry I wasn't actually connecting to the database. Thanks for the help guys – Mukul Raina Mar 06 '15 at 01:37
  • I'm actually running into another issue right now. For the last 2 tests, I get the following message: "Uncaught AssertionError: expected null to exist" Any idea what it could mean? – Mukul Raina Mar 06 '15 at 01:47

1 Answers1

1

As pointed out in the comments, you didn't actually connect to the mongodb database. All your requests will be queued by Mongoose and never be executed until you connect to the database (thus generating the timeouts in your tests).

EDIT As for your second problem, you are expecting error to exist when it is actually not generating any errors. This line is failing your tests:

should.exist(err);

You should check your model. In your third test case you require a user to have an email, but your model doesn't enforce that. Same thing for the password. Also, you are not making the password empty in your test.

victorkt
  • 13,992
  • 9
  • 52
  • 51