Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing $interval in Jasmine/ Karma

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?

like image 837
KArneaud Avatar asked May 24 '16 00:05

KArneaud


People also ask

How do I check Jasmine setTimeout?

it("causes a timeout to be called", function(done) { setTimeout(function() { timerCallback(); }, 100); setTimeout(function() { expect(timerCallback).

How do you write unit test cases in Karma Jasmine?

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.

What is default capture time out in karma?

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.


1 Answers

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.

like image 66
logee Avatar answered Sep 25 '22 02:09

logee