Testing Angular devices Service using $ timeout with a Jasmine Mock

I have a function inside one of my angular services that I would like to repeat at regular intervals. I would like to do this using $ timeout. It looks something like this:

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

I'm at a standstill about how unit test is with Jasmine at the moment - How to do this? If I use $timeout.flush() , then function calls are executed endlessly. If I use a Jasmine mock, $timeout does not seem to be affected. Basically, if I can get this working, I should be fine to go:

 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(); }); }); 

These two options work, but do not help me:

 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(); }); }); 

Thanks in advance!

+42
javascript angularjs jasmine
Jul 02 '13 at 6:21
source share
2 answers

Do not run the Async test using a Jasmine watch. Instead, use $timeout.flush() to keep the test flow synchronous. It may be a little tricky to configure, but once you get it, your tests will be faster and more controlled.

Here is an example test that takes this approach: https://github.com/angular/angular.js/blob/master/test/ngAnimate/animateSpec.js#L618

+50
Sep 14 '13 at 14:45
source share

@matsko's answer led me on the right track. I thought I would post my β€œcomplete” solution so that it would be easier to find the answer.

Thing to check

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

Test

 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(); }); }); 
+41
Aug 04 '14 at 17:33
source share



All Articles