unit-testingnode.jsmongoosevowsexpresso

Testing MongooseJs Validations


Does anyone know how to test Mongoose Validations?

Example, I have the following Schema (as an example):

var UserAccount = new Schema({
    user_name       : { type: String, required: true, lowercase: true, trim: true, index: { unique: true }, validate: [ validateEmail, "Email is not a valid email."]  }, 
    password        : { type: String, required: true },
    date_created    : { type: Date, required: true, default: Date.now }
}); 

The validateEmail method is defined as such:

// Email Validator
function validateEmail (val) {
    return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(val);
}

I want to test the validations. The end result is that I want to be able to test the validations and depending on those things happening I can then write other tests which test the interactions between those pieces of code. Example: User attempts to sign up with the same username as one that is taken (email already in use). I need a test that I can actually intercept or see that the validation is working WITHOUT hitting the DB. I do NOT want to hit Mongo during these tests. These should be UNIT tests NOT integration tests. :)

Thanks!


Solution

  • I had the same problem recently.

    First off I would recommend testing the validators on their own. Just move them to a separate file and export the validation functions that you have.

    This easily allows your models to be split into separate files because you can share these validators across different models.

    Here is an example of testing the validators on their own:

    // validators.js
    exports.validatePresenceOf = function(value){ ... }
    exports.validateEmail = function(value){ ... }
    

    Here is a sample test for this (using mocha+should):

    // validators.tests.js
    var validator = require('./validators')
    
    // Example test
    describe("validateEmail", function(){
       it("should return false when invalid email", function(){
           validator.validateEmail("asdsa").should.equal(false)
       })      
    })
    

    Now for the harder part :)

    To test your models being valid without accessing the database there is a validate function that can be called directly on your model.

    Here is an example of how I currently do it:

    describe("validating user", function(){  
      it("should have errors when email is invalid", function(){
        var user = new User();
        user.email = "bad email!!" 
        user.validate(function(err){      
          err.errors.email.type.should.equal("Email is invalid")
        })
      })
    
      it("should have no errors when email is valid", function(){
        var user = new User();
        user.email = "test123@email.com"
        user.validate(function(err){
          assert.equal(err, null)
        })
      })
    })   
    

    The validator callback gets an error object back that looks something like this:

    { message: 'Validation failed',
        name: 'ValidationError',
        errors: 
            { email: 
               { message: 'Validator "Email is invalid" failed for path email',
                 name: 'ValidatorError',
                 path: 'email',
                 type: 'Email is invalid' 
               } 
            } 
    }
    

    I'm still new to nodeJS and mongoose but this is how I'm testing my models + validators and it seems to be working out pretty well so far.