3

I would like to unit test an Angular.js $timeout to check that it has been called with the correct duration/delay value.

The assertion would look something like this:

expect($timeout).toHaveBeenCalledWith(n);

My Angular code looks roughly like the following:

$timeout(function() {
    // do something
}, attrs.timeout || 30000);

I want to ensure that without an override (attrs.timeout) it is called with 30000 and with the override it is called with that override.

I have tried a decorator like this:

// from: http://stackoverflow.com/a/21536245/633056
beforeEach(module(function($provide) {
    $provide.decorator('$timeout', function($delegate) {
        return jasmine.createSpy($delegate);
    });
}));

Plus several other methods but I cannot seem to get it to work.

I am using Angular 1.3.20, Jasmine 2.3.4

Any suggestions gratefully received.

atwright147
  • 3,694
  • 4
  • 31
  • 57

1 Answers1

4

You can try create a mock for the timeout and set expectation on the spy. For checking the first argument you can use the matcher jasmine.any(Function) and second argument with expected delay.

Example:

describe('Ctrl', function() {
  beforeEach(module('test-app'));
  var ctrl, timeout;
  beforeEach(inject(function($rootScope, $controller) {
    scope = $rootScope.$new();

    //Create Spy
    timeout = jasmine.createSpy('$timeout');

    ctrl = $controller('loadingCtr', {
      '$timeout': timeout
    });

    $rootScope.$digest();
  }));

  //Your expectations
  it('should call timeout with passed in delay', function() {
    ctrl.callTimeout(1000);
    expect(timeout).toHaveBeenCalledWith(jasmine.any(Function), 1000);
  });
  it('should call timeout with default delay', function() {
    ctrl.callTimeout();
    expect(timeout).toHaveBeenCalledWith(jasmine.any(Function), 30000);
  });

});

Demo

If it is a directive just override timeout with your spy.

var dir, 
      timeout = jasmine.createSpy('$timeout'), scope;

  beforeEach(module('test-app', function ($provide) {
       $provide.value('$timeout', timeout);
   }));

  beforeEach(inject(function($rootScope, $compile) {
    scope = $rootScope.$new();
    $compile('<test-timeout timeout="6000"></test-timeout>')(scope);
    scope.$apply();
  }));

  it('should call timeout with passed in delay', function() {
     expect(timeout).toHaveBeenCalledWith(jasmine.any(Function), 6000);
  });

Demo

PSL
  • 123,204
  • 21
  • 253
  • 243