I\'m trying to test my AngularJS controller with Jasmine, using Karma. But a $timeout
which works well in real-life, crashes my tests.
Controller:
According to the Angular JS documentation for $timeout, you can use $timeout.flush()
to synchronously flush the queue of deferred functions.
Try updating your test to this:
it('should do stuff', function() {
expect($scope.stuffDone).toBeFalsy();
$scope.doStuff();
expect($scope.stuffDone).toBeFalsy();
$timeout.flush();
expect($scope.stuffDone).toBeTruthy();
});
Here is a plunker showing both your original test failing and the new test passing.
As $timeout
is just a wrapper for window.setTimeout
, you can use jasmines Clock.useMock()
which mocks the window.setTimeout
beforeEach(function() {
jasmine.Clock.useMock();
});
it('should do stuff', function() {
$scope.doStuff();
jasmine.Clock.tick(251);
expect($scope.stuffDone).toBeTruthy();
});
As noted in one of the comments, Jasmine setTimeout
mock is not being used because angular's JS mock $timeout
service is used instead. Personally, I'd rather use Jasmine's because its mocking method lets me test the length of the timeout. You can effectively circumvent it with a simple provider in your unit test:
module(function($provide) {
$provide.constant('$timeout', setTimeout);
});
Note: if you go this route, be sure to call $scope.apply()
after jasmine.Clock.tick.