2

我有以下裝飾器,它圍繞原始$timeout$rootScope。在控制器內部使用時,在範圍銷燬時取消$timeout承諾將有所幫助。

angular.module('MyApp').config(['$provide', function ($provide) { 

    $provide.decorator('$rootScope', ['$delegate', function ($delegate) { 

     Object.defineProperty($delegate.constructor.prototype, 'timeout', { 
      value: function (fn, number, invokeApply) { 
       var $timeout = angular.injector(['ng']).get('$timeout'), 
        promise; 

       promise = $timeout(fn, number, invokeApply); 

       this.$on('$destroy', function() { 
        $timeout.cancel(promise); 
       }); 
      }, 
      enumerable: false 
     }); 

     return $delegate; 
    }]); 

}]); 

但我該如何正確地單元測試呢?我有兩個測試,我應該在這裏做... 1)檢查是否調用$rootScope.timeout()時調用了原始$timeout,以及2)檢查範圍銷燬時是否取消承諾。

這裏是我目前的測試套件這樣的:

describe('MyApp', function() { 
    var $rootScope; 

    beforeEach(function() { 
     module('MyApp'); 

     inject(['$rootScope', function (_$rootScope_) { 
      $rootScope = _$rootScope_; 
     }]); 
    }); 

    describe('$timeout', function() { 
     it('<something>', function() { 
      $rootScope.timeout(function() {}, 2500); 

      // Test if the real $timeout was called with above parameters 

      $rootScope.$destroy(); 

      // Test if the $timeout promise was destroyed 
     }); 
    }); 

}); 

,這確實是給我100%覆蓋率的唯一的事情。但那不是我想要的......我如何正確地測試這個?

回答

0

由於沒有人能夠幫助我,我真的想完成這件事,我終於找到了我自己的解決方案。我不確定這是最好的解決方案,但我認爲它確實有效。

這裏是我如何解決它:

describe('MyApp', function() { 
    var $rootScope, 
     $timeout, 
     deferred; 

    beforeEach(function() { 
     module('MyApp'); 

     inject(['$rootScope', '$q', function (_$rootScope_, _$q_) { 
      $rootScope = _$rootScope_; 
      deferred = _$q_.defer(); 
     }]); 

     $timeout = jasmine.createSpy('$timeout', { 
      cancel: jasmine.createSpy('$timeout.cancel') 
     }).and.returnValue(deferred.promise); 

     spyOn(angular, 'injector').and.returnValue({ 
      get: function() { 
       return $timeout; 
      } 
     }); 
    }); 

    describe('$timeout', function() { 
     it('should set the timeout with the specified arguments', function() { 
      $rootScope.timeout(angular.noop, 250, false); 
      expect($timeout).toHaveBeenCalledWith(angular.noop, 250, false); 
     }); 

     it('should cancel the timeout on scope destroy event', function() { 
      $rootScope.timeout(angular.noop, 250, false); 
      $rootScope.$destroy(); 

      expect($timeout.cancel).toHaveBeenCalledWith(deferred.promise); 
     }); 
    }); 

});