I have a simple factory
angular.module('myApp.dice',[]).factory('Dice', ['$interval', function($interval){
return {
rollDice: function(){
return $interval(function(c){
count++;
}, 100, 18, false, 0);
}
};
}]);
In my test case I have
describe('rolling dice', function(){
var promise, promiseCalled = false, notify = false;
beforeEach(inject(function(){
promise = Dice.rollDice();
promise.then(function(){
promiseCalled = true;
});
}));
it('should invoke a promise', inject(function(){
expect(promise).toBeDefined();
}));
it('should set promiseCalled', inject(function($rootScope, $interval){
expect(promiseCalled).toEqual(true);
}));
});
How do I trigger the interval or resolve the promise? to get the test to be true?
it("causes a timeout to be called", function(done) { setTimeout(function() { timerCallback(); }, 100); setTimeout(function() { expect(timerCallback).
Create an Angular project with jasmine and karma By doing this, the jasmine and karma configuration is resolved for us. Install and create a new project with angular-cli: Install npm -g @angular/cli. Ng new angular-unit-testing angular unit-testing.
The captureTimeout value represents the maximum boot-up time allowed for a browser to start and connect to Karma. If any browser does not get captured within the timeout, Karma will kill it and try to launch it again and, after three attempts to capture it, Karma will give up.
See plunker
You need to use '$interval.flush' from angularjs-mocks and then test for the result. I've taken the liberty to assign count
to the dice object because it's undefined in your code sample.
Is there any reason why $interval
is called with invokeApply = false
? because then you have to manually call $apply
.
The test case would be:
describe('rolling dice', function(){
var $interval, $rootScope, dice;
beforeEach(module('plunker'));
beforeEach(inject(function(_$interval_, _$rootScope_, _Dice_){
$interval = _$interval_;
$rootScope = _$rootScope_;
dice = _Dice_;
}));
it('should increment count', inject(function(){
dice.rollDice();
// Move forward by 100 milliseconds
$interval.flush(100);
// Need to call apply because $interval was called with invokeApply = false
$rootScope.$apply();
expect(dice.count).toBe(1);
}));
});
with factory:
app.factory('Dice', ['$interval', function($interval){
var self= {
count: 0,
rollDice: function(){
return $interval(function() {
self.count++;
}, 100, 18, false, 0);
}
};
return self;
}]);
EDIT:
I prefer testing the result of a function call but perhaps you have a use case for testing that a promise function is called so this might be what you're looking for. From the angular docs on $interval
it says it returns
A promise which will be notified on each iteration.
Keyword being notified. And from the promise API the arguments for then
are
then(successCallback, errorCallback, notifyCallback)
i.e. the third call back function notifyCallback
is called for each iteration of $interval
. So the test would look something like this:
it('should set promiseCalled', function(){
var promiseCalled = false;
dice.rollDice().then(null, null, function() {
promiseCalled = true;
});
$interval.flush(100);
$rootScope.$apply();
expect(promiseCalled).toBe(true);
});
If you want to test for a resolved promise, then it would look something like this:
it('should resolve promise', function(){
var promiseCalled = false;
var resolvedData = null;
$q.when('Some Data').then(function(data) {
promiseCalled = true;
resolvedData = data;
});
$rootScope.$apply();
expect(promiseCalled).toBe(true);
expect(resolvedData).toBe('Some Data');
});
I've updated the plunker with these test cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With