【问题标题】:TypeError: Cannot read property 'defaultPrevented' of undefinedTypeError:无法读取未定义的属性“defaultPrevented”
【发布时间】:2014-03-28 19:33:26
【问题描述】:

我在进行以下测试时收到此错误:

it('should call pauseAnimationInterval if in focus', inject(function(SearchBoxData, intervalManager, $timeout){
  SearchBoxData.init_array = [];
  SearchBoxData.inFocus = true;
  SearchBoxData.init(intervalManager);
  console.log(intervalManager.pauseTimeout);
  console.log(intervalManager.pauseTimeoutTime);
  console.log($timeout);
  $timeout.flush(intervalManager.pauseTimeoutTime+1);
  expect(rootScope.$broadcast).toHaveBeenCalledWith('onPauseInterval', intervalManager.loopIndex);
}));

它在$timeout.flush(intervalManager.pauseTimeoutTime+1); 上中断 $timeout 方法在intervalManager.pauseAnimationInterval() 中调用,它位于SearchBoxData.init(intervalManager) 内部:

intervalManager.pauseAnimationInterval = function (){

  intervalManager.safeCancel(intervalManager.continueInterval);
  intervalManager.safeCancel(intervalManager.initInterval);
  intervalManager.initInterval = null;
  intervalManager.continueInterval = null;

  intervalManager.pauseTimeout = $timeout(function () {
    if(intervalManager.inFocus === true){
      intervalManager.loopIndex += 1;
      if(intervalManager.loopIndex >= intervalManager.maxLoopIndex){
        intervalManager.loopIndex = 0;
      }
      $rootScope.$broadcast("onPauseInterval", intervalManager.loopIndex);
      intervalManager.continueAnimationInterval();
    }else{
      // Important condition: retry after the timeout if no focus
      // main reason of glitch
      intervalManager.pauseAnimationInterval();
    }
  }, intervalManager.pauseTimeoutTime);

};

我之前没有收到此错误,我不确定我做错了什么。

更新:这是一个带有未缩小版 angularJS 的堆栈跟踪:

at /Users/foo/projects/bar/vendor/assets/javascripts/angular.js:9268:88
at Scope.$eval (/Users/foo/projects/bar/vendor/assets/javascripts/angular.js:11986:28)
at Scope.$digest (/Users/foo/projects/bar/vendor/assets/javascripts/angular.js:11812:31)
at Scope.$apply (/Users/foo/projects/bar/vendor/assets/javascripts/angular.js:12092:24)
at Object.fn (/Users/foo/projects/bar/vendor/assets/javascripts/angular.js:13627:36)
at Function.self.defer.flush (/Users/foo/projects/bar/spec/javascripts/lib/angular/angular-mocks.js:126:32)
at Function.$delegate.flush (/Users/foo/projects/bar/spec/javascripts/lib/angular/angular-mocks.js:1689:20)
at null.<anonymous> (/Users/foo/projects/bar/spec/javascripts/unit/services/searchboxdata_service_spec.js:71:16)

更新 2:我将其追溯到 SearchBoxData 工厂的注入。我不确定它有什么问题。每当我创建 $timeout 实例并使用 flush 方法时,只需注入它就会导致错误。

更新 3:我注意到如果我在其中一个依赖项中注入 $location 或 $route 就会发生这种情况(间接依赖项,它发生在我到处使用的一些基本服务中)。

更新 4:这是一个重现它的 plunker! http://plnkr.co/edit/7XweXI?p=info

【问题讨论】:

  • 抱歉这个答案,显然没有引起足够的重视。以后再看;)
  • 你有这个失败的测试的小提琴或 plunker 吗?
  • @dmahapatro 我管理了一个重现错误的 plunker。查看我的编辑。
  • plunker 没有通过。我猜它没有正确保存。尝试在单独的浏览器中打开链接。我总是在发布任何演示代码之前这样做,以确保链接提供的 plunker 有我的更改。 :)
  • @dmahapatro 你现在看到了吗?我无法保存它,所以我分叉了它。

标签: angularjs settimeout


【解决方案1】:

$broadcast()'d 或 $emit()'d 的作用域事件是同步的,并在完成时返回事件对象。

Angular 中有些东西依赖于返回的事件对象,比如 ngRoute。

因此,您可以做些什么来解决此问题,只需在创建间谍时添加 andCallThrough(),以便它调用原始函数并产生返回值。

或者,如果你不想使用真正的 $broadcast,你可以使用andCallFake() 提供一个可以返回任何你想要的东西的假函数。

例子:

beforeEach(function(){
  module('MyApp');
  inject(function($injector){
    rootScope = $injector.get('$rootScope');
    spyOn(rootScope,'$broadcast').andCallThrough(); // will prevent the reference error
  })
});

【讨论】:

  • 非常感谢@chronicsalsa,这个问题困扰了我好几天。
  • 好收获。如果没有那个有问题的笨蛋,我就不会得到那个。 :) 正如我们所知,一个很好的问题解决了一半。 ;)
  • 请注意,在 Jasmine 2.0 及更高版本中,语法为 and.callThrough();
  • 请更新您的答案以使用 Jasmine 2.0 语法。
猜你喜欢
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 2019-08-19
  • 1970-01-01
相关资源
最近更新 更多