Revision a4d33f3dd2ab890357a4e491811daed9c18922b8 authored by Aaron Heckmann on 16 April 2012, 17:18:17 UTC, committed by Aaron Heckmann on 24 May 2012, 20:19:46 UTC
1 parent 89ffb2f
Raw File
document.test.js

/**
 * Module dependencies.
 */

var start = require('./common')
  , should = require('should')
  , mongoose = start.mongoose
  , Schema = mongoose.Schema
  , ObjectId = Schema.ObjectId
  , Document = require('../lib/document')
  , DocumentObjectId = mongoose.Types.ObjectId;

/**
 * Test Document constructor.
 */

function TestDocument () {
  Document.apply(this, arguments);
};

/**
 * Inherits from Document.
 */

TestDocument.prototype.__proto__ = Document.prototype;

/**
 * Set a dummy schema to simulate compilation.
 */

var em = new Schema({ title: String, body: String });
em.virtual('works').get(function () {
  return 'em virtual works'
});
var schema = TestDocument.prototype.schema = new Schema({
    test    : String
  , oids    : [ObjectId]
  , numbers : [Number]
  , nested  : {
        age   : Number
      , cool  : ObjectId
      , deep  : { x: String }
      , path  : String
      , setr  : String
    }
  , nested2 : {
        nested: String
      , yup   : {
            nested  : Boolean
          , yup     : String
          , age     : Number
        }
    }
  , em: [em]
});

schema.virtual('nested.agePlus2').get(function (v) {
  return this.nested.age + 2;
});
schema.virtual('nested.setAge').set(function (v) {
  this.nested.age = v;
});
schema.path('nested.path').get(function (v) {
  return this.nested.age + (v ? v : '');
});
schema.path('nested.setr').set(function (v) {
  return v + ' setter';
});

/**
 * Method subject to hooks. Simply fires the callback once the hooks are
 * executed.
 */

TestDocument.prototype.hooksTest = function(fn){
  fn(null, arguments);
};

/**
 * Test.
 */

module.exports = {
  'test shortcut getters': function(){
    var doc = new TestDocument();
    doc.init({
        test    : 'test'
      , oids    : []
      , nested  : {
            age   : 5
          , cool  : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c')
          , path  : 'my path'
        }
    });

    doc.test.should.eql('test');
    doc.oids.should.be.an.instanceof(Array);
    (doc.nested.age == 5).should.be.true;
    DocumentObjectId.toString(doc.nested.cool).should.eql('4c6c2d6240ced95d0e00003c');
    doc.nested.agePlus2.should.eql(7);
    doc.nested.path.should.eql('5my path');
    doc.nested.setAge = 10;
    (doc.nested.age == 10).should.be.true;
    doc.nested.setr = 'set it';
    doc.getValue('nested.setr').should.eql('set it setter');

    var doc2 = new TestDocument();
    doc2.init({
        test    : 'toop'
      , oids    : []
      , nested  : {
            age   : 2
          , cool  : DocumentObjectId.fromString('4cf70857337498f95900001c')
          , deep  : { x: 'yay' }
        }
    });

    doc2.test.should.eql('toop');
    doc2.oids.should.be.an.instanceof(Array);
    (doc2.nested.age == 2).should.be.true;

    // GH-366
    should.strictEqual(doc2.nested.bonk, undefined);
    should.strictEqual(doc2.nested.nested, undefined);
    should.strictEqual(doc2.nested.test, undefined);
    should.strictEqual(doc2.nested.age.test, undefined);
    should.strictEqual(doc2.nested.age.nested, undefined);
    should.strictEqual(doc2.oids.nested, undefined);
    should.strictEqual(doc2.nested.deep.x, 'yay');
    should.strictEqual(doc2.nested.deep.nested, undefined);
    should.strictEqual(doc2.nested.deep.cool, undefined);
    should.strictEqual(doc2.nested2.yup.nested, undefined);
    should.strictEqual(doc2.nested2.yup.nested2, undefined);
    should.strictEqual(doc2.nested2.yup.yup, undefined);
    should.strictEqual(doc2.nested2.yup.age, undefined);
    doc2.nested2.yup.should.be.a('object');

    doc2.nested2.yup = {
        age: 150
      , yup: "Yesiree"
      , nested: true
    };

    should.strictEqual(doc2.nested2.nested, undefined);
    should.strictEqual(doc2.nested2.yup.nested, true);
    should.strictEqual(doc2.nested2.yup.yup, "Yesiree");
    (doc2.nested2.yup.age == 150).should.be.true;
    doc2.nested2.nested = "y";
    should.strictEqual(doc2.nested2.nested, "y");
    should.strictEqual(doc2.nested2.yup.nested, true);
    should.strictEqual(doc2.nested2.yup.yup, "Yesiree");
    (doc2.nested2.yup.age == 150).should.be.true;

    DocumentObjectId.toString(doc2.nested.cool).should.eql('4cf70857337498f95900001c');

    doc.oids.should.not.equal(doc2.oids);
  },

  'test shortcut setters': function () {
    var doc = new TestDocument();

    doc.init({
        test    : 'Test'
      , nested  : {
            age   : 5
        }
    });

    doc.isModified('test').should.be.false;
    doc.test = 'Woot';
    doc.test.should.eql('Woot');
    doc.isModified('test').should.be.true;

    doc.isModified('nested.age').should.be.false;
    doc.nested.age = 2;
    (doc.nested.age == 2).should.be.true;
    doc.isModified('nested.age').should.be.true;
  },

  'test accessor of id': function () {
    var doc = new TestDocument();
    doc._id.should.be.an.instanceof(DocumentObjectId);
  },

  'test shortcut of id hexString': function () {
    var doc = new TestDocument()
      , _id = doc._id.toString();
    doc.id.should.be.a('string');
  },

  'test toObject clone': function(){
    var doc = new TestDocument();
    doc.init({
        test    : 'test'
      , oids    : []
      , nested  : {
            age   : 5
          , cool  : new DocumentObjectId
        }
    });

    var copy = doc.toObject();

    copy.test._marked = true;
    copy.nested._marked = true;
    copy.nested.age._marked = true;
    copy.nested.cool._marked = true;

    should.strictEqual(doc._doc.test._marked, undefined);
    should.strictEqual(doc._doc.nested._marked, undefined);
    should.strictEqual(doc._doc.nested.age._marked, undefined);
    should.strictEqual(doc._doc.nested.cool._marked, undefined);
  },

  'toObject options': function () {
    var doc = new TestDocument();

    doc.init({
        test    : 'test'
      , oids    : []
      , em      : [{ title: 'title' }]
      , nested  : {
            age   : 5
          , cool  : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c')
          , path  : 'my path'
        }
    });

    var clone = doc.toObject({ getters: true, virtuals: false });

    clone.test.should.eql('test');
    clone.oids.should.be.an.instanceof(Array);
    (clone.nested.age == 5).should.be.true;
    DocumentObjectId.toString(clone.nested.cool).should.eql('4c6c2d6240ced95d0e00003c');
    clone.nested.path.should.eql('5my path');
    should.equal(undefined, clone.nested.agePlus2);
    should.equal(undefined, clone.em[0].works);

    clone = doc.toObject({ virtuals: true });

    clone.test.should.eql('test');
    clone.oids.should.be.an.instanceof(Array);
    (clone.nested.age == 5).should.be.true;
    DocumentObjectId.toString(clone.nested.cool).should.eql('4c6c2d6240ced95d0e00003c');
    clone.nested.path.should.eql('my path');
    clone.nested.agePlus2.should.eql(7);
    clone.em[0].works.should.eql('em virtual works');

    clone = doc.toObject({ getters: true });

    clone.test.should.eql('test');
    clone.oids.should.be.an.instanceof(Array);
    (clone.nested.age == 5).should.be.true;
    DocumentObjectId.toString(clone.nested.cool).should.eql('4c6c2d6240ced95d0e00003c');
    clone.nested.path.should.eql('5my path');
    clone.nested.agePlus2.should.eql(7);
    clone.em[0].works.should.eql('em virtual works');
  },

  'test hooks system': function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , awaiting = 0
      , called = false;

    // serial
    doc.pre('hooksTest', function(next){
      steps++;
      setTimeout(function(){
        // make sure next step hasn't executed yet
        steps.should.eql(1);
        next();
      }, 50);
    });

    doc.pre('hooksTest', function(next){
      steps++;
      next();
    });

    // parallel
    doc.pre('hooksTest', true, function(next, done){
      steps++;
      steps.should.eql(3);
      setTimeout(function(){
        steps.should.eql(4);
      }, 10);
      setTimeout(function(){
        steps++;
        done();
      }, 110);
      next();
    });

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      setTimeout(function(){
        steps.should.eql(4);
      }, 10);
      setTimeout(function(){
        steps++;
        done();
      }, 110);
      next();
    });

    doc.hooksTest(function(err){
      should.strictEqual(err, null);
      steps++;
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(7);
      called.should.be.true;
    });
  },

  'test that calling next twice doesnt break': function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', function(next){
      steps++;
      next();
      next();
    });

    doc.pre('hooksTest', function(next){
      steps++;
      next();
    });

    doc.hooksTest(function(err){
      should.strictEqual(err, null);
      steps++;
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(3);
      called.should.be.true;
    });
  },

  'test that calling done twice doesnt break': function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done();
      done();
    });

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done();
      done();
    });

    doc.hooksTest(function(err){
      should.strictEqual(err, null);
      steps++;
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(3);
      called.should.be.true;
    });
  },

  'test that calling done twice on the same doesnt mean completion':
  function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done();
      done();
    });

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
    });

    doc.hooksTest(function(err){
      should.strictEqual(err, null);
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(2);
      called.should.be.false;
    });
  },

  'test hooks system errors from a serial hook': function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', function(next){
      steps++;
      next();
    });

    doc.pre('hooksTest', function(next){
      steps++;
      next(new Error);
    });

    doc.pre('hooksTest', function(next){
      steps++;
    });

    doc.hooksTest(function(err){
      err.should.be.an.instanceof(Error);
      steps++;
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(3);
      called.should.be.true;
    });
  },

  'test hooks system erros from last serial hook': function(beforeExit){
    var doc = new TestDocument()
      , called = false;

    doc.pre('hooksTest', function(next){
      next(new Error());
    });

    doc.hooksTest(function(err){
      err.should.be.an.instanceof(Error);
      called = true;
    });

    beforeExit(function(){
      called.should.be.true;
    });
  },

  'test mutating incoming args via middleware': function (beforeExit) {
    var doc = new TestDocument();

    doc.pre('set', function(next, path, val){
      next(path, 'altered-' + val);
    });

    doc.set('test', 'me');

    beforeExit(function(){
      doc.test.should.equal('altered-me');
    });
  },
  
  'test hooks system errors from a parallel hook': function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done();
    });

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done();
    });

    doc.pre('hooksTest', true, function(next, done){
      steps++;
      next();
      done(new Error);
    });

    doc.hooksTest(function(err){
      err.should.be.an.instanceof(Error);
      steps++;
      called = true;
    });

    beforeExit(function(){
      steps.should.eql(4);
      called.should.be.true;
    });
  },
  
  'test that its not necessary to call the last next in the parallel chain':
  function(beforeExit){
    var doc = new TestDocument()
      , steps = 0
      , called = false;

    doc.pre('hooksTest', function(next, done){
      next();
      done();
    });

    doc.pre('hooksTest', function(next, done){
      done();
    });

    doc.hooksTest(function(){
      called = true;
    });

    beforeExit(function(){
      called.should.be.true;
    });
  },

  'test passing two arguments to a method subject to hooks and return value':
  function (beforeExit) {
    var doc = new TestDocument()
      , called = false;

    doc.pre('hooksTest', function (next) {
      next();
    });

    doc.hooksTest(function (err, args) {
      args.should.have.length(2);
      args[1].should.eql('test');
      called = true;
    }, 'test')
    
    beforeExit(function () {
      called.should.be.true;
    });
  },

  // gh-746
  'hooking set works with document arrays': function () {
    var db = start();

    var child = new Schema({ text: String });

    child.pre('set', function (next, path, value, type) {
      next(path, value, type);
    });

    var schema = new Schema({
        name: String
      , e: [child]
    });

    var S = db.model('docArrayWithHookedSet', schema);

    var s = new S({ name: "test" });
    s.e = [{ text: 'hi' }];
    s.save(function (err) {
      db.close();
      should.strictEqual(null, err);
    });
  },

  'test jsonifying an object': function () {
    var doc = new TestDocument({ test: 'woot' })
      , oidString = DocumentObjectId.toString(doc._id);

    // convert to json string
    var json = JSON.stringify(doc);

    // parse again
    var obj = JSON.parse(json);

    obj.test.should.eql('woot');
    obj._id.should.eql(oidString);
  },

  'toObject should not set undefined values to null': function () {
    var doc = new TestDocument()
      , obj = doc.toObject();

    delete obj._id;
    obj.should.eql({ numbers: [], oids: [], em: [] });
  },

  // GH-209
  'MongooseErrors should be instances of Error': function () {
    var MongooseError = require('../lib/error')
      , err = new MongooseError("Some message");
    err.should.be.an.instanceof(Error);
  },
  'ValidationErrors should be instances of Error': function () {
    var ValidationError = Document.ValidationError
      , err = new ValidationError(new TestDocument);
    err.should.be.an.instanceof(Error);
  },

  'methods on embedded docs should work': function () {
    var db = start()
      , ESchema = new Schema({ name: String })

    ESchema.methods.test = function () {
      return this.name + ' butter';
    }
    ESchema.statics.ten = function () {
      return 10;
    }

    var E = db.model('EmbeddedMethodsAndStaticsE', ESchema);
    var PSchema = new Schema({ embed: [ESchema] });
    var P = db.model('EmbeddedMethodsAndStaticsP', PSchema);

    var p = new P({ embed: [{name: 'peanut'}] });
    should.equal('function', typeof p.embed[0].test);
    should.equal('function', typeof E.ten);
    p.embed[0].test().should.equal('peanut butter');
    E.ten().should.equal(10);

    // test push casting
    p = new P;
    p.embed.push({name: 'apple'});
    should.equal('function', typeof p.embed[0].test);
    should.equal('function', typeof E.ten);
    p.embed[0].test().should.equal('apple butter');

    db.close();
  },

  'setting a positional path does not cast value to array': function () {
    var doc = new TestDocument;
    doc.init({ numbers: [1,3] });
    doc.numbers[0].should.eql(1);
    doc.numbers[1].valueOf().should.eql(3);
    doc.set('numbers.1', 2);
    doc.numbers[0].should.eql(1);
    doc.numbers[1].valueOf().should.eql(2);
  },

  'no maxListeners warning should occur': function () {
    var db = start();

    var traced = false;
    var trace = console.trace;

    console.trace = function () {
      traced = true;
      console.trace = trace;
    }

    var schema = new Schema({
        title: String
      , embed1: [new Schema({name:String})]
      , embed2: [new Schema({name:String})]
      , embed3: [new Schema({name:String})]
      , embed4: [new Schema({name:String})]
      , embed5: [new Schema({name:String})]
      , embed6: [new Schema({name:String})]
      , embed7: [new Schema({name:String})]
      , embed8: [new Schema({name:String})]
      , embed9: [new Schema({name:String})]
      , embed10: [new Schema({name:String})]
      , embed11: [new Schema({name:String})]
    });

    var S = db.model('noMaxListeners', schema);

    var s = new S({ title: "test" });
    db.close();
    traced.should.be.false
  },

  'isSelected': function () {
    var doc = new TestDocument();

    doc.init({
        test    : 'test'
      , numbers : [4,5,6,7]
      , nested  : {
            age   : 5
          , cool  : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c')
          , path  : 'my path'
          , deep  : { x: 'a string' }
        }
      , notapath: 'i am not in the schema'
      , em: [{ title: 'gocars' }]
    });

    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.true;
    doc.isSelected('numbers').should.be.true;
    doc.isSelected('oids').should.be.true; // even if no data
    doc.isSelected('nested').should.be.true;
    doc.isSelected('nested.age').should.be.true;
    doc.isSelected('nested.cool').should.be.true;
    doc.isSelected('nested.path').should.be.true;
    doc.isSelected('nested.deep').should.be.true;
    doc.isSelected('nested.nope').should.be.true; // not a path
    doc.isSelected('nested.deep.x').should.be.true;
    doc.isSelected('nested.deep.x.no').should.be.true;
    doc.isSelected('nested.deep.y').should.be.true; // not a path
    doc.isSelected('noway').should.be.true; // not a path
    doc.isSelected('notapath').should.be.true; // not a path but in the _doc
    doc.isSelected('em').should.be.true;
    doc.isSelected('em.title').should.be.true;
    doc.isSelected('em.body').should.be.true;
    doc.isSelected('em.nonpath').should.be.true; // not a path

    var selection = {
        'test': 1
      , 'numbers': 1
      , 'nested.deep': 1
      , 'oids': 1
    }

    doc = new TestDocument(undefined, selection);

    doc.init({
        test    : 'test'
      , numbers : [4,5,6,7]
      , nested  : {
            deep  : { x: 'a string' }
        }
    });

    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.true;
    doc.isSelected('numbers').should.be.true;
    doc.isSelected('oids').should.be.true; // even if no data
    doc.isSelected('nested').should.be.true;
    doc.isSelected('nested.age').should.be.false;
    doc.isSelected('nested.cool').should.be.false;
    doc.isSelected('nested.path').should.be.false;
    doc.isSelected('nested.deep').should.be.true;
    doc.isSelected('nested.nope').should.be.false;
    doc.isSelected('nested.deep.x').should.be.true;
    doc.isSelected('nested.deep.x.no').should.be.true;
    doc.isSelected('nested.deep.y').should.be.true;
    doc.isSelected('noway').should.be.false;
    doc.isSelected('notapath').should.be.false;
    doc.isSelected('em').should.be.false;
    doc.isSelected('em.title').should.be.false;
    doc.isSelected('em.body').should.be.false;
    doc.isSelected('em.nonpath').should.be.false;

    var selection = {
        'em.title': 1
    }

    doc = new TestDocument(undefined, selection);

    doc.init({
        em: [{ title: 'one' }]
    });

    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.false;
    doc.isSelected('numbers').should.be.false;
    doc.isSelected('oids').should.be.false;
    doc.isSelected('nested').should.be.false;
    doc.isSelected('nested.age').should.be.false;
    doc.isSelected('nested.cool').should.be.false;
    doc.isSelected('nested.path').should.be.false;
    doc.isSelected('nested.deep').should.be.false;
    doc.isSelected('nested.nope').should.be.false;
    doc.isSelected('nested.deep.x').should.be.false;
    doc.isSelected('nested.deep.x.no').should.be.false;
    doc.isSelected('nested.deep.y').should.be.false;
    doc.isSelected('noway').should.be.false;
    doc.isSelected('notapath').should.be.false;
    doc.isSelected('em').should.be.true;
    doc.isSelected('em.title').should.be.true;
    doc.isSelected('em.body').should.be.false;
    doc.isSelected('em.nonpath').should.be.false;

    var selection = {
        'em': 0
    }

    doc = new TestDocument(undefined, selection);
    doc.init({
        test    : 'test'
      , numbers : [4,5,6,7]
      , nested  : {
            age   : 5
          , cool  : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c')
          , path  : 'my path'
          , deep  : { x: 'a string' }
        }
      , notapath: 'i am not in the schema'
    });

    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.true;
    doc.isSelected('numbers').should.be.true;
    doc.isSelected('oids').should.be.true;
    doc.isSelected('nested').should.be.true;
    doc.isSelected('nested.age').should.be.true;
    doc.isSelected('nested.cool').should.be.true;
    doc.isSelected('nested.path').should.be.true;
    doc.isSelected('nested.deep').should.be.true;
    doc.isSelected('nested.nope').should.be.true;
    doc.isSelected('nested.deep.x').should.be.true;
    doc.isSelected('nested.deep.x.no').should.be.true;
    doc.isSelected('nested.deep.y').should.be.true;
    doc.isSelected('noway').should.be.true;
    doc.isSelected('notapath').should.be.true;
    doc.isSelected('em').should.be.false;
    doc.isSelected('em.title').should.be.false;
    doc.isSelected('em.body').should.be.false;
    doc.isSelected('em.nonpath').should.be.false;

    var selection = {
        '_id': 0
    }

    doc = new TestDocument(undefined, selection);
    doc.init({
        test    : 'test'
      , numbers : [4,5,6,7]
      , nested  : {
            age   : 5
          , cool  : DocumentObjectId.fromString('4c6c2d6240ced95d0e00003c')
          , path  : 'my path'
          , deep  : { x: 'a string' }
        }
      , notapath: 'i am not in the schema'
    });

    doc.isSelected('_id').should.be.false;
    doc.isSelected('nested.deep.x.no').should.be.true;

    doc = new TestDocument({ test: 'boom' });
    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.true;
    doc.isSelected('numbers').should.be.true;
    doc.isSelected('oids').should.be.true;
    doc.isSelected('nested').should.be.true;
    doc.isSelected('nested.age').should.be.true;
    doc.isSelected('nested.cool').should.be.true;
    doc.isSelected('nested.path').should.be.true;
    doc.isSelected('nested.deep').should.be.true;
    doc.isSelected('nested.nope').should.be.true;
    doc.isSelected('nested.deep.x').should.be.true;
    doc.isSelected('nested.deep.x.no').should.be.true;
    doc.isSelected('nested.deep.y').should.be.true;
    doc.isSelected('noway').should.be.true;
    doc.isSelected('notapath').should.be.true;
    doc.isSelected('em').should.be.true;
    doc.isSelected('em.title').should.be.true;
    doc.isSelected('em.body').should.be.true;
    doc.isSelected('em.nonpath').should.be.true;

    var selection = {
        '_id': 1
    }

    doc = new TestDocument(undefined, selection);
    doc.init({ _id: 'test' });

    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.false;

    doc = new TestDocument({ test: 'boom' }, true);
    doc.isSelected('_id').should.be.true;
    doc.isSelected('test').should.be.true;
    doc.isSelected('numbers').should.be.true;
    doc.isSelected('oids').should.be.true;
    doc.isSelected('nested').should.be.true;
    doc.isSelected('nested.age').should.be.true;
    doc.isSelected('nested.cool').should.be.true;
    doc.isSelected('nested.path').should.be.true;
    doc.isSelected('nested.deep').should.be.true;
    doc.isSelected('nested.nope').should.be.true;
    doc.isSelected('nested.deep.x').should.be.true;
    doc.isSelected('nested.deep.x.no').should.be.true;
    doc.isSelected('nested.deep.y').should.be.true;
    doc.isSelected('noway').should.be.true;
    doc.isSelected('notapath').should.be.true;
    doc.isSelected('em').should.be.true;
    doc.isSelected('em.title').should.be.true;
    doc.isSelected('em.body').should.be.true;
    doc.isSelected('em.nonpath').should.be.true;
  },

  'unselected required fields should pass validation': function () {
    var db = start()
      , Tschema = new Schema({ name: String, req: { type: String, required: true }})
      , T = db.model('unselectedRequiredFieldValidation', Tschema);

    var t = new T({ name: 'teeee', req: 'i am required' });
    t.save(function (err) {
      should.strictEqual(null, err);
      T.findById(t).select('name').exec(function (err, t) {
        should.strictEqual(null, err);
        should.strictEqual(undefined, t.req);
        t.name = 'wooo';
        t.save(function (err) {
          should.strictEqual(null, err);

          T.findById(t).select('name').exec(function (err, t) {
            should.strictEqual(null, err);
            t.req = undefined;
            t.save(function (err) {
              err = String(err);
              var invalid  = /Validator "required" failed for path req/.test(err);
              invalid.should.be.true;
              t.req = 'it works again'
              t.save(function (err) {
                should.strictEqual(null, err);

                T.findById(t).select('_id').exec(function (err, t) {
                  should.strictEqual(null, err);
                  t.save(function (err) {
                    db.close();
                    should.strictEqual(null, err);
                  });
                });
              });
            });
          });
        });
      });
    });
  }
};
back to top