Testing MongooseJs Validations
Asked Answered
P

2

7

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!

Peasant answered 10/2, 2012 at 3:39 Comment(0)
S
11

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 = "[email protected]"
    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.

Strontium answered 15/2, 2012 at 6:15 Comment(1)
For the last couple of tests where you call user.validate(): I'm running my tests using grunt and Jasmine Node and my assertions were never being hit to fail a build. I had to setup my tests for the callbacks to get the assertions to be run properly. In my case, using jasmine-node, I added a jasmine.asyncSpecWait() to the end of each test and a jasmine.asyncSpecDone() inside the validate callback. Then everything was good. Very helpful answer!Conlon
C
2

You should use validate() method as a promise and test it with a tool that makes asserts for async stuff (ex: Chai as Promised).

First of all, require a promise library and switch out to the promise provider (for example Q):

mongoose.Promise = require('q').Promise;

Afterwards just, use asserts about promises:

    it('should show errors on wrong email', function() {
        user = new UserModel({
            email: 'wrong email adress'
        });
        return expect(user.validate()).to.be.rejected;
    });

    it('should not show errors on valid email adress', function() {
        user = new UserModel({
            email: '[email protected]'
        });
        return expect(user.validate()).to.be.fulfilled;
    });
Calley answered 29/8, 2015 at 6:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.