mousetree
mousetree

Reputation: 105

Mongoose custom validation not working in controller

My mongoose model contains a field that is only required if another field equals a specific value (i.e. it is conditional).

In this example, I have an item which has an itemType of 'typeA' or 'typeB'. The field someField is only required for 'typeB'.

In my tests, the validation seems to work when testing against the model directly. However, the validation is not trigger in the controller.

My model is as follows:

var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

var ItemSchema = new Schema({
  name: {
    type: String,
    trim: true,
    required: true
  },
  itemType: {
    type: String,
    enum: ['typeA', 'typeB'],
    required: true
  },
  someField: String
});

ItemSchema
  .path('someField')
  .validate(function(value, respond) {
    if (this.itemType === 'typeA') { return respond(true); }
    return respond(validatePresenceOf(value));
  }, 'someField cannot be blank for typeB');

function validatePresenceOf(value) {
  return value && value.length;
}

module.exports = mongoose.model('Item', ItemSchema);

In my unit test for the model:

it('should fail when saving typeB without someField', function(done) {

  var item = new Item({
    name: 'test',
    itemType: 'typeB'
  });

  item.save(function(err){
    should.exist(err);
    done();
  });

});

The above unit test works with no problem. However, when testing the API itself, Mongoose does not raise an error. The controller is supposed to return a 500 error if it cannot save:

exports.create = function(req, res) {
  var item = new Item(req.body);
  item.save(function(err, data) {
    if (err) { return res.json(500, err); }
    return res.json(200, data);
  });
};

However, the following test always returns a 200:

var request = require('supertest');

describe('with invalid fields', function() {
  it('should respond with a 500 error', function(done) {
    request(app)
      .post('/api/item')
      .send({
        name: 'test',
        itemType: 'typeB'
        })
      .expect(500)
      .end(function(err, res) {
        if (err) return done(err);
        return done();
        });
      });
  });
});

I'm not sure what I'm doing wrong, it seems the Mongoose validation is not being triggered when I save in the controller.

Upvotes: 3

Views: 1525

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151132

The implementation is the wrong way around here. You don't validate on 'someField' but on the value that is passed to 'itemType'. The reason why is since you have not supplied any value for 'someField' then the validator is never called since there is nothing defined.

So the test runs the other way around, as well as correcting your validatePresenceOf() function:

itemSchema.path('itemType').validate(function(value) {
  if ( value === 'typeA' )
    return true;
  console.log( validatePresenceOf(this.someField) );
  return validatePresenceOf(this.someField);

}, 'someField cannot be blank for itemType: "typeB"');

function validatePresenceOf(value) {
  if ( value != undefined )
    return value && value.length
  else
    return false;
}

That will throw an error correctly is 'itemType' is set to 'typeB' and the 'someField' has no value at all.

Upvotes: 3

Related Questions