Testing the handling of a custom event in Jasmine

joecritch picture joecritch · Jun 23, 2013 · Viewed 18k times · Source

I am wanting to ensure that a object's method gets called as an event handler, when a custom jQuery event is triggered; but the unit test is seemingly returning a false-negative, as my implementation works well.

(This is part of a test suite that uses Twitter Flight & the Flight Jasmine extensions, but this is just a vanilla Jasmine spy.)

describe('listening for uiNeedsPlan event', function() {

var spy;
beforeEach(function() {
  spy = spyOn(this.component, 'getPlan');
  $(document).trigger('uiNeedsPlan');
});

it('gets the current plan', function() {
  expect(spy).toHaveBeenCalled();
});

});

This results in a failed spec:

Expected spy getPlan to have been called.

Here is a snippet from my code implementation of my Flight component (which works successfully):

this.after('initialize', function () {
  this.on(document, 'uiNeedsPlan', this.getPlan);
});

Answer

Tom Hamshere picture Tom Hamshere · Jun 23, 2013

Before I go in to the details of why this isn't working, I'd first like to point out that it's bad practice to test whether this method has been executed. You should be testing the component's interface - its input and output and its effect on the DOM. How it does what it does (which internal methods it calls, its internal state) is irrelevant.

As to why it's not working: When you create the spy, you are spying on the unbound version of the component method. When the component is instantiated, methods are bound to the instance and assigned to callbacks. It is impossible (afaik) to access these bound methods after the component is instantiated.

Instead, you need to spy on the the prototype before the component instance is attached to the DOM. Also, you don't seem to be calling setupComponent at all, so this.component won't exist yet anyway.

var spy;

beforeEach(function () {
    spy = spyOn(this.Component, 'getPlan');
    setupComponent();
    $(document).trigger('uiNeedsPlan');
});
it('executes getPlan', function() {
    expect(spy).toHaveBeenCalled();
});