2012-04-30 10 views
9

Provare a verificare che un gestore eventi venga chiamato su un elemento cliccato con Jasmine. Avere un oggetto "Pad" che contiene un elemento DOM "PadElement", che viene cliccato. Il gestore di eventi è un metodo sull'oggetto Pad:Jasmine non può spiare il gestore di eventi?

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="http://www.w3.org/2000/svg"; 
    var pad=document.createElementNS(NS,"svg"); 
    pad.setAttributeNS(null, 'id', 'pad'); 
    graphDiv.appendChild(pad); 
    pad.addEventListener('click', clickHandler) 
    return pad; 
} 

Il test Jasmine:

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"); 
     simulateClick(testPad.padElement); 
     //testPad.clickHandler(); 
     expect(testPad.clickHandler).toHaveBeenCalled(); 
    }); 

Tuttavia, il test fallisce. Si noti che il listener di eventi viene chiamato (console.log scrive correttamente con un clic del mouse e con simulateClick), E se io richiama semplicemente testPad.clickHandler() direttamente la spia di Jasmine può prenderlo. Ma cosa succede durante il test vero? Il richiamo del gestore di eventi viene trasferito su un oggetto diverso in fase di runtime? Qual è il modo giusto per farlo?

risposta

6

In realtà si sta testando che GRAPH.padElement chiama la dotazione clickHandler e non quello di this.clickHandlerGRAPH.Pad è chiamato da GRAPH.padElement. Come vorrei farlo

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() { 
     simulateClick(testPad.padElement); 
     expect(clickHandlerSpy).toHaveBeenCalled(); 
    }); 

Questo può sembrare poco diverso da quello che stai cercando di ottenere. Ma nel mondo dei test unitari ideale dovresti testare ogni unità in modo indipendente, quindi prima verificherei che padElement faccia ciò che deve fare (come sopra) e poi scriva un altro test per assicurarci che passi il gestore corretto a padElement. Ora per farlo non creerei padElement direttamente da GRAPH.Pad ma in qualche modo lo inietto dall'esterno e poi lo schernisco nelle specifiche di jasmine. Se non sei chiaro su questa parte fammi sapere e posso mettere insieme del codice per te.

2

Per aggiungere una spiegazione generica di più:

È necessario spiare prima di fissare la funzione come listener di eventi.

Alcuni pseudo-codice:

it("succeeds", function(){ 
    var o = {} 
    o.f = function() { console.log("event caught!");} //your eventHandler 
    spyOn(o, "f").and.callThrough(); //o.f is now a spy 
    addEventListener('click', o.f); //spy listens for event 

    fireEvent("click"); //"event caught!" is written to console 

    expect(o.f).toHaveBeenCalled(); //success, we're happy 
}); 



it("fails", function(){ 
    var o = {} 
    o.f = function() { console.log("event caught!");} //your eventHandler 
    addEventListener('click', o.f); //your eventHandler function listens for event 
    spyOn(o, "f").and.callThrough(); //o.f is now a spy 

    fireEvent("click"); //"event caught!" is written to console 

    expect(o.f).toHaveBeenCalled(); //fail, we waste a couple of hours not understanding why 
}); 

Quindi, se sai che il tuo gestore viene chiamato, ma la spia non registra come .tohaveBeenCalled() controllo ciò che accade prima: la vostra spia o l'assegnazione di chi ascolta. La spia deve venire prima.

Problemi correlati