Spying on Function Calls in Jasmine Doesn’t Work as You Expect It To

Say you want to test that a function is called in your javascript code. What could be simpler, you say. Just write a simple Jasmine spec, throw a spy in, and you are set. That’s what I thought, before stumbling on a weird issue. OK, let’s setup the code:

var Foo = (function() {
  funcB = function (){
    console.log('B - I was just called');
  },
  
  funcA = function (){
    funcB();
  }

  return {
    funcA:funcA,
    funcB:funcB
  }
 
})();

And now, let’s write the Jasmine spec that checks that funcB() is being called from funcA()

describe("when calling funcA", function () {
  it("funcB should be called", function() {
    var spyEvent = spyOn(Foo, 'funcB');
    Foo.funcA();
    expect(spyEvent).toHaveBeenCalled();
  });
});

Smiling nonchalantly your run you spec, and get this:

> B – I was just called

> Expected spy funcB to have been called but it was never called.

You can see that funcB()is being called, but our spy doesn’t catch it. What’s going on?

After spending some time tinkering with the code and looking for answers online, I finally found this comment that hinted to the solution. Turns out “Jasmine spies will only replace the function on the returned object”. So to make sure your spy will catch the call, you need to change your original code so that funcB()is called through this:

var Foo = (function() {
  funcB = function (){
    console.log('B - I was just called');
  },
  
  funcA = function (){
    this.funcB();
  }
 
  return {
    funcA:funcA,
    funcB:funcB
  }
 
})();

And now the world makes sense again:

2 Comments

  1. Laura

    Thank you a lot for this article!

    • Mike

      Thanks Laura, glad you found it useful

Comments are closed