Domanda

When testing part of an AngularJS Application which uses both $timeout and $timeout.cancel with Jasmine's spyOn method.

describe('<whatever>', function() {

  beforeEach(function() {
    spyOn(this, '$timeout').andCallThrough();
    spyOn(this.$timeout, 'cancel').andCallThrough();
    this.createController();
  });

  it('should <whatever>', function() {
    expect(this.$timeout).toHaveBeenCalled();
    expect(this.$timeout.cancel).toHaveBeenCalled();
  });

});

You should encounter the following error in your application code, which is using what your test injected into it.

TypeError: 'undefined' is not a function (evaluating '$timeout.cancel(timeoutPromise)');
È stato utile?

Soluzione

If you were to run console.log(Object.keys(this.$timeout)); in your test suite, you will see the following output;

LOG: ['identity', 'isSpy', 'plan', 'mostRecentCall', 'argsForCall', 'calls', 'andCallThrough', 'andReturn', 'andThrow', 'andCallFake', 'reset', 'wasCalled', 'callCount', 'baseObj', 'methodName', 'originalValue']

$timeout is a function which AngularJS is also decorating—since functions are objects—with a cancel method. Because this isn't that common a thing to do, Jasmine replaces rather than augments $timeout with it's spying implementation - clobbering $timeout.cancel.

A workaround for this is to put the cancel spy back again after $timeout has been overwritten by Jasmine's $timeout spy, as follows;

describe('<whatever>', function() {

  beforeEach(function() {
    spyOn(this.$timeout, 'cancel').andCallThrough();
    var $timeout_cancel = this.$timeout.cancel;
    spyOn(this, '$timeout').andCallThrough();
    this.$timeout.cancel = $timeout_cancel;
    this.createController();
  });

  it('should <whatever>', function() {
    expect(this.$timeout).toHaveBeenCalled();
    expect(this.$timeout.cancel).toHaveBeenCalled();
  });

});

Altri suggerimenti

This worked for me for $interval, so it should work for $timeout. (jasmine 2)

var $intervalSpy = jasmine.createSpy('$interval', $interval).and.callThrough();

Then I can do both:

expect($intervalSpy.cancel).toHaveBeenCalledTimes(1);
expect($intervalSpy).toHaveBeenCalledTimes(1);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top