unitarias pruebas javascript angularjs jasmine

javascript - pruebas unitarias ionic 3



Servicio angular de pruebas unitarias que usa $ timeout con el reloj simulado de Jasmine (2)

Tengo una función dentro de uno de mis servicios angulares que me gustaría que me llamen repetidamente en un intervalo regular. Me gustaría hacer esto usando $ timeout. Se ve algo como esto:

var interval = 1000; // Or something var _tick = function () { $timeout(function () { doStuff(); _tick(); }, interval); }; _tick();

Estoy sorprendido de cómo hacer una prueba de unidad con Jasmine en este momento. ¿Cómo hago esto? Si uso $timeout.flush() , las llamadas a la función se producen de forma indefinida. Si uso el reloj simulado de Jasmine, el $timeout parece no verse afectado. Básicamente, si puedo hacer que esto funcione, debería ser bueno:

describe("ANGULAR Manually ticking the Jasmine Mock Clock", function() { var timerCallback, $timeout; beforeEach(inject(function($injector) { $timeout = $injector.get(''$timeout''); timerCallback = jasmine.createSpy(''timerCallback''); jasmine.Clock.useMock(); })); it("causes a timeout to be called synchronously", function() { $timeout(function() { timerCallback(); }, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.Clock.tick(101); expect(timerCallback).toHaveBeenCalled(); }); });

Estas dos variaciones funcionan, pero no me ayudan:

describe("Manually ticking the Jasmine Mock Clock", function() { var timerCallback; beforeEach(function() { timerCallback = jasmine.createSpy(''timerCallback''); jasmine.Clock.useMock(); }); it("causes a timeout to be called synchronously", function() { setTimeout(function() { timerCallback(); }, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.Clock.tick(101); expect(timerCallback).toHaveBeenCalled(); }); }); describe("ANGULAR Manually flushing $timeout", function() { var timerCallback, $timeout; beforeEach(inject(function($injector) { $timeout = $injector.get(''$timeout''); timerCallback = jasmine.createSpy(''timerCallback''); })); it("causes a timeout to be called synchronously", function() { $timeout(function() { timerCallback(); }, 100); expect(timerCallback).not.toHaveBeenCalled(); $timeout.flush(); expect(timerCallback).toHaveBeenCalled(); }); });

¡Gracias por adelantado!


La respuesta de @ matsko me llevó por el camino correcto. Pensé que publicaría mi solución "completa" para que sea más fácil encontrar la respuesta.

Lo que hay que probar

angular.module("app").service("MyService", function() { return { methodThatHasTimeoutAndReturnsAPromise: function($q, $timeout) { var deferred = $q.defer(); $timeout(function() { deferred.resolve(5); }, 2000); return deferred.promise; } }; });

La prueba

describe("MyService", function() { var target, $timeout; beforeEach(inject(function(_$timeout_, MyService) { $timeout = _$timeout_; target = MyService; })); beforeEach(function(done) { done(); }); it("equals 5", function(done) { target.methodThatHasTimeoutAndReturnsAPromise().then(function(value) { expect(value).toBe(5); done(); }); $timeout.flush(); }); });


No hagas tu prueba Async usando el reloj de Jasmine. En su lugar, use $timeout.flush() para mantener sincrónicamente el flujo de la prueba. Puede ser un poco difícil de configurar, pero una vez que lo obtenga, sus pruebas serán más rápidas y más controladas.

Aquí hay un ejemplo de una prueba que lo hace utilizando este enfoque: https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618