Jasmine spyOn mongoose save

I would like to poke fun at the save () function of a Mongoose model. The function I want to test looks like this in the user.js file:

var User = import('User.js')

post: function(req, res) {
  var user = new User({
      password    : req.body.password,
      email       : req.body.email,
  });
  user.save( function(err) {
    if (err) {
      ....
    } else {
      ....
    }
  });

      

I tried to write a test that looks like this in another user_spec.js file:

var Hander = require('user.js')

it('works properly', function() {
  spyOn(User, 'save').andReturn(null)
  Handler.post(req, res);
});

      

but this gives me an error:

save() method does not exist

      

I did some more digging and it looks like the user model itself doesn't have a save () method, it does an instance. That would mean I should mock the user constructor, but I'm having a lot of problems with it. Other messages refer to statements like:

spyOn(window, User)

      

to fix this, but in NodeJS the global (the window equivalent here) doesn't have a user, since I'm importing as a variable. Is it possible to mock the constructor to give me something with a mock save ()? I also looked at an npm module called rewire , but I was hoping I could do it without mocking and replacing the entire user module in my handler.

+3


source to share


3 answers


This does not solve the problem of mocking the local variable, but it does solve the problem of unit testing the creation of new documents.

When creating a new document, it is better to use Model.create (). It can be mocked efficiently, and it's just less code. The correct way to handle this and test it would be as follows:

var User = import('User.js')

post: function(req, res) {
  User.create({
      password    : req.body.password,
      email       : req.body.email,
  }, function(err) {
    if (err) {
      ....
    } else {
      ....
    }
  });
});

      



Relevant test:

var Hander = require('user.js')

it('works properly', function() {
  spyOn(User, 'create').andReturn(null)
  Handler.post(req, res);
});

      

Hopefully this workaround will help other people get frustrated with jasmine and mongoose unit testing.

+1


source


You can only replace the function with the spy after creating the object. Hence this will work:

var user = new User(…);
spyOn(user, save).…;
doSomething();

      

where it won't:



spyOn(User, save).…
doSomething()

      

Of course, you can change the function inside mongoose that creates the object save function ... but you probably don't want to go there.

0


source


In a normal world, you can do this.

spyOn(Model.prototype, 'save')

However Mongoose tries to overload all of its model functions to work like node.js and Promises callbacks at the same time. To do this, they manipulate the prototype in a way that is hard to predict without reading the actual model code ( https://github.com/Automattic/mongoose/blob/master/lib/model.js ).

Here's an example that actually worked for me.

spyOn(Model.prototype, '$__save').and.callFake(function (options, callback) { callback(); });

For the record, I am using Mongoose with Promises in my application code.

0


source







All Articles