2015-06-11 19 views
8

Sto provando a utilizzare Jasmine 2.0 per scrivere test di unità per qualche logica in un'app AngularJS, ma la logica è all'interno di un listener di eventi. Dal controller:Testing postMessage con Jasmine async non funziona

window.addEventListener('message', function(e) { 
    if (e.data === "sendMessage()") { 
     $scope.submit(); 
    } 
    }, false); 

E dal file di test:

describe("post message", function() { 
    beforeEach(function(done) { 
     var controller = createController(controllerParams); 
     spyOn($scope, 'submit'); 
     window.postMessage('sendMessage()', '*'); 
     done(); 
    }); 

    it('should submit on a sent message', function (done) { 
     expect($scope.submit).toHaveBeenCalled(); 
     done(); 
    }); 
    }); 

Ma la prova non riesce, la spia non essere colpito. Informazioni aggiuntive da inserire nelle istruzioni di debug della console:

  • window.addEventListener nel controller Viene richiamato.
  • I blocchi beforeEach e it vengono entrambi richiamati.
  • Durante il test non viene richiamato il gestore di messaggi sopra riportato nel controller.
  • Il messaggio inviato in questo test viene infine ricevuto dal gestore messaggi, più volte, ma non prima che il test termini.

Qual è il mio test mancante qui?

+0

Non dovresti chiamare postMessage su * un'altra * finestra rispetto a quella che riceverà l'evento? (per esempio, creando un popup, come è fatto su https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage?redirectlocale=en-US&redirectslug=DOM%2Fwindow.postMessage) – phtrivier

+0

Cambiato provato a un postmessage da un popup fuori dalla finestra invece che da un messaggio post dalla finestra, ma tutto ciò che è cambiato è che, invece di ricevere il messaggio troppo tardi, non riceve affatto il messaggio. –

+0

@AlanGordon: hai già trovato una soluzione per questo? Sto avendo gli stessi problemi ;-) –

risposta

6

Sta accadendo perché nel vostro beforeEach blocco si chiama window.postMessage() (che è asincrona e non si sa quando si sta andando esecuzione) e quindi si chiama done() subito dopo come sarebbe il codice sincrono. Ma window.postMessage() async, e in pratica è necessario chiamare done() quando l'operazione asincrona è completa. Si potrebbe essere fatto in questo modo:

beforeEach(function(done) { 
    spyOn(someObject, 'submit').and.callFake(function() { 
     done(); 
    }); 
}); 

Così, quando la vostra spia esegue, quindi operazione asincrona è considerata completa.

Questo potrebbe essere espressa ancora più breve:

beforeEach(function(done) { 
    spyOn(someObject, 'submit').and.callFake(done); 
}); 

Ecco il codice completo:

var someObject = { 
    submit: function() { 
    console.log('Submit'); 
    } 
}; 

window.addEventListener('message', function(e) { 
    if (e.data === "sendMessage()") { 
    someObject.submit(); 
    } 
}, false); 

// Test 

describe('window.postMessage', function() { 

    beforeEach(function(done) { 
    spyOn(someObject, 'submit').and.callFake(function() { 
     done(); 
    }); 
    window.postMessage('sendMessage()', '*'); 
    }); 

    it('should submit on a sent message', function() { 
    expect(someObject.submit).toHaveBeenCalled(); 
    }); 

}); 

Vedere un lavoro JS Bin: http://jsbin.com/xikewogagu/1/edit?html,js,console,output

non ho usato angolare in questo campione perché è riproducibile con un JS puro.

+0

Questo era esattamente! Grazie per l'aiuto. –