jeffersii jeffersii - 1 year ago 82
Javascript Question

Jasmine can't spy on event handler?

Trying to test that an event handler gets called on a clicked element with Jasmine. Have a "Pad" object that contains a DOM element "PadElement", which gets clicked. The event handler is a method on the Pad object:

GRAPH.Pad = function(graphDiv, graph) {
this.graph = graph;

this.clickHandler = function(e) {
console.log('padElement clickHandler called');
//this.graph.createVertex(e.clientX, e.clientY);
this.padElement = GRAPH.padElement(graphDiv, this.clickHandler);

GRAPH.padElement = function(graphDiv, clickHandler) {
//Initialize pad
var NS="";
var pad=document.createElementNS(NS,"svg");
pad.setAttributeNS(null, 'id', 'pad');
pad.addEventListener('click', clickHandler)
return pad;

The Jasmine test:

var testDiv = document.createElement('div');
var testGraph = new GRAPH.Graph(testDiv);
var testPad = new GRAPH.Pad(testDiv, testGraph);

it('has its clickHandler function called when its padElement is clicked',
function() {
spyOn(testPad, "clickHandler");

However, the test FAILS. Note that the event listener does get called (console.log writes successfully with a mouse click and with simulateClick), AND if I just call the testPad.clickHandler() directly Jasmine's spy can pick it up. But what happens during the actual test? Does the event handler invocation get transferred to a different object at runtime? What's the right way to do this?

Answer Source

You are actually testing that GRAPH.padElement calls the supplied clickHandler and not that this.clickHandler of GRAPH.Pad is called by GRAPH.padElement. How I would do that is

var testDiv = document.createElement('div');
var clickHandlerSpy = jasmine.CreateSpy();
var padelement = padElement(testDiv , clickHandlerSpy);

  it('has its clickHandler function called when its padElement is clicked',
    function() {

This may sound little different to what you are trying to achieve. But in ideal unit testing world you should be testing each unit independently, so I would first test that padElement does what it's supposed to do (as above) and then write another test to make sure GRAPH.Pad is passing correct handler to padElement. Now to do that I would not create padElement directly from within GRAPH.Pad but somehow inject it from outside and then mock it in the jasmine specs. If you are not clear on this part let me know and I can put some code together for you.