Question

I'm having trouble getting jasmine spies to work for my mongoose documents. I have a method set up in my User schema like so:

User.methods.doSomething = function() {
   // implementation
}

User is a dependency of the model I'm currently testing and I want to ensure that doSomething is being called correctly. In my tests I have something like:

spyOn(User.schema.methods, 'doSomething')

If I log out User.schema.methods.doSomething I get the function I expect but when I run the code that calls that method the original implementation is invoked and not the spy. Also I can't do:

spyOn(userInstance, 'doSomething')

In my tests as the userInstance isn't being exposed and I really want to avoid exposing it. Essentially I want to set up a spy on the User document (instance?) prototype. Is that possible?

Was it helpful?

Solution

Mongoose is copying the methods defined in the schema to the model prototype and only those methods are used. So even though

User.schema.methods.doSomething === User.prototype.doSomething

if you set:

spyOn(User.schema.methods, 'doSomething')

it won't get called - User.prototype.doSomething will. Your guess was right, you should just use:

spyOn(User.prototype, 'doSometing');

Don't forget to use and.callThrough if you want to have the original method called after setting up the spy (I fell for that).

OTHER TIPS

Unfortunately, I couldn't get the spyOn to work on the model prototype. It might be because my 'model' is actually a mongoose subdocument.

Instead I opted for a proxy function, which I spyOn instead. It's an extra function call, which is a bit annoying, but it works.

// index.js
Controller._performClone = function(doc) {
  return doc.clone();
};

Controller.clone = function(id) {
  var child = parent.children.id(req.params.id);
  return Controller._performClone(child);
};


// spec.js
describe('Cloning', function() {
  it('should clone a document', function(done) {
    spyOn(Controller, '_performClone').and.returnValue('cloned');
    var rtn = Controller.clone('1');
    expect(rtn).toBe('cloned');

    // `correctChild` is the one you expect with ID '1'
    expect(Controller._performClone).toHaveBeenCalledWith(correctChild);
  });
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top