Issues with Jasmine's spyOn toHaveBeenCalled on a prototypal method
Asked Answered
R

1

6

My example of spying on a method is failing with "Expected spy handle_click to have been called." when it should pass. However, I am getting the console log "Foo handle_click called!", so I know it's being called.

Foo.js

function Foo() {
    this.$btn = $('<a href="#">Foo</a>');
    this.$btn.on('click', this.handle_click);
};
Foo.prototype.handle_click = function(evt) {
    evt.preventDefault();
    console.log('Foo handle_click called!');
};

Foo_spec.js:

it('should be called when trigger is clicked', function() {
    var foo = new Foo();
    spyOn( foo, 'handle_click' ).andCallThrough();
    foo.$btn.click();
    expect( foo.handle_click ).toHaveBeenCalled();
});

I am using jasmine-1.2.0, jasmin-html and jasmine-jquery, but not jasmine-sinon; at-least I don't think it's bundled in there. Any help is much appreciated!

Update This was answered below. However, I wanted to document the solution in the case of a jQuery Plugin:

Foo.js:

function Foo() { ... }
Foo.prototype.handle_click = function(evt) { ... }

$.fn.foo = function(options) {
    return new Foo(this, options || {});
};

$.fn.foo.prototype = Foo.prototype;

Foo_spec.js:

it('should be called when clicked', function() {
    spyOn( $.fn.foo.prototype, 'handle_click');
    var plugin = $('#selector-for-plugin').foo();
    plugin.$btn.click();
    expect( plugin.handle_click ).toHaveBeenCalled();
});
Robichaud answered 11/5, 2013 at 22:21 Comment(0)
N
2

The problem is that you bind the handle_click function in the constructor. So when you create a new instance a reference to the function is binded to the event. After that you replace the foo.handle_click with a spy. But this will not effect the function that was binded to the event as this is still your original function. You have to spy on the Foo.prototype.handle_click function before you create the instance, so the spied function can be bound to the event.

it('should be called when trigger is clicked', function() {
  spyOn( Foo.prototype, 'handle_click' );
  var foo = new Foo();
  foo.$btn.click();
  expect( foo.handle_click ).toHaveBeenCalled();
});
Norsworthy answered 12/5, 2013 at 7:1 Comment(1)
Nice! Per your suggestion I added the prototype to my jQuery Plugin so it was accessible to assign the spy before instantiating it: $.fn.foo = function(options) { return new Foo(this, options || {}); }; $.fn.foo = Foo.prototype; Thanks!Robichaud

© 2022 - 2024 — McMap. All rights reserved.