Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 802
Donn Felker Avatar asked Feb 10 '12 03:02

Donn Felker


People also ask

Does mongoose have built in validation?

Mongoose has several built-in validators. All SchemaTypes have the built-in required validator. The required validator uses the SchemaType's checkRequired() function to determine if the value satisfies the required validator. Numbers have min and max validators.

What are some validations used in the schema?

Schema validation lets you create validation rules for your fields, such as allowed data types and value ranges. MongoDB uses a flexible schema model, which means that documents in a collection do not need to have the same fields or data types by default.

What is the need of Mongoose .how it is useful for validation?

Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node. js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB. MongoDB is a schema-less NoSQL document database.

What is Mongoosejs?

What is Mongoose? Mongoose is a Node. js-based Object Data Modeling (ODM) library for MongoDB. It is akin to an Object Relational Mapper (ORM) such as SQLAlchemy for traditional SQL databases. The problem that Mongoose aims to solve is allowing developers to enforce a specific schema at the application layer.


2 Answers

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.

like image 155
Craig MacGregor Avatar answered Oct 16 '22 07:10

Craig MacGregor


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;
    });
like image 2
Alexandr Lazarev Avatar answered Oct 16 '22 09:10

Alexandr Lazarev