Node.js – Stubbing a Mongoose model using Sinon

mongoosenode.jssinon

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?

Best Solution

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");
});