6

I am trying to stub the mongoose dependency used in this object:

var Page = function(db) {

    var mongoose = db || require('mongoose');

    if(!this instanceof Page) {
        return new Page(db);
    }

    function save(params) {
        var PageSchema = mongoose.model('Page');

        var pageModel = new PageSchema({
            ...
        });

        pageModel.save();
    }

    Page.prototype.save = save;
}

module.exports = Page;

Using the answer for this question, I've tried doing this:

mongoose = require 'mongoose'
sinon.stub mongoose.Model, 'save'

But I got the error:

TypeError: Attempted to wrap undefined property save as function

I also tried this:

sinon.stub PageSchema.prototype, 'save'

And then I got the error:

TypeError: Should wrap property of object

Can anyone help with this? What am I doing wrong?

Community
  • 1
  • 1
thitemple
  • 5,833
  • 4
  • 42
  • 67

3 Answers3

7

I've analysed mongoose source and don't think this is possible. Save function is not defined on model, but dynamically generated by hooks npm which enables pre/post middleware functionality.

However, you can stub save on instance like this:

page = new Page();
sinon.stub(page, 'save', function(cb){ cb(null) })

UPDATE: Stubbing out pageModel

First, you need to make pageModel accessible by setting it as own property of Page (this.pageModel = xxx). Then, you can stub it like shown bellow:

mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
mongoose.set('debug', true);

schema = new mongoose.Schema({title: String});
mongoose.model('Page', schema);


var Page = function(db) {

  var mongoose = db || require('mongoose');

  if(!this instanceof Page) {
    return new Page(db);
  }

  var PageSchema = mongoose.model('Page');
  this.pageModel = new PageSchema();

  function save(params, cb) {
    console.log("page.save");
    this.pageModel.set(params);
    this.pageModel.save(function (err, product) {
      console.log("pageModel.save");
      cb(err, product);
    });
  }

  Page.prototype.save = save;
};


page = new Page();

sinon = require('sinon');
sinon.stub(page.pageModel, 'save', function(cb){
  cb("fake error", null);
});

page.save({ title: 'awesome' }, function (err, product) {
  if(err) return console.log("ERROR:", err);
  console.log("DONE");
});
Milovan Zogovic
  • 1,541
  • 2
  • 16
  • 24
  • I tried doing this, but I am receiving an error saying that: Object save has no method 'save'. I've called mongoose.model('Page'), created and instance of that and then I stubied it. – thitemple May 24 '13 at 13:55
  • Hmm.. are you trying to stub out the `pageModel.save`? – Milovan Zogovic May 24 '13 at 14:09
  • All I want is to avoid going to the database. It doesn't matter how. First I tried to stub de mongoose.model. Now I'm trying to stub pageModel.save – thitemple May 24 '13 at 15:34
  • I don't actually like to expose the PageSchema, but this way it works. – thitemple May 24 '13 at 17:42
6

I recommend you to use mock instead of stub, that will check the method really exists on the original object.

var page = new Page();

// If you are using callbacks, use yields so your callback will be called
sinon.mock(page)
  .expects('save')
  .yields(someError, someResult);

// If you are using Promises, use 'resolves' (using sinon-as-promised npm) 
sinon.mock(page)
  .expects('save')
  .resolves(someResult);

Take a look to sinon-mongoose. You can expects chained methods (on both, Mongoose Models and Documents) with just a few lines (there are working examples on the repo).

Gon
  • 627
  • 7
  • 6
0
page = new Page();
sinon.stub(page, 'save', function(cb){ cb(null) })

Above code is deprecated.

Please try to add fake function for your stub as below -

sinon.stub(page, 'save').callsFake(function(cb){
      // do your Fake code
      cb(null)
})
Hemang
  • 85
  • 3
  • 11