如何使用Jasmine的去抖功能测试AngularJS手表

时间:2014-06-11 16:07:08

标签: angularjs jasmine karma-jasmine

我有一个带有手表的控制器,它使用来自lodash的debounce延迟过滤列表500ms。

$scope.$watch('filter.keywords', _.debounce(function () {
  $scope.$apply(function () {
    $scope.filtered = _.where(list, filter);
  });
}, 500));

我正在尝试编写一个Jasmine测试,模拟输入未找到的过滤器关键字,然后找到找到的关键字。

我最初的尝试是在为关键字指定新值后使用$ digest,我认为这是因为去抖动而无效。

it('should filter list by reference', function () {
  expect(scope.filtered).toContain(item);
  scope.filter.keywords = 'rubbish';
  scope.$digest();
  expect(scope.filtered).not.toContain(item);
  scope.filter.keywords = 'test';
  scope.$digest();
  expect(scope.filtered).toContain(item);
});

所以我尝试使用$ timeout,但这也不起作用。

it('should filter list by reference', function () {
  expect(scope.filtered).toContain(item);
  $timeout(function() {
    scope.filter.keywords = 'rubbish';
  });
  $timeout.flush();
  expect(scope.filtered).not.toContain(item);
  $timeout(function() {
    scope.filter.keywords = 'test';
  });
  $timeout.flush();
  expect(scope.filtered).toContain(item);
});

我还尝试给$ timeout一个大于debounce设置的500ms的值。

其他人如何解决这个问题?

编辑:我找到了一个解决方案,即将期望包装在$ timeout函数中,然后在范围内调用$ apply。

it('should filter list by reference', function () {
  expect(scope.filtered).toContain(item);
  scope.filter.keywords = 'rubbish';
  $timeout(function() {
    expect(scope.filtered).not.toContain(item);
  });
  scope.$apply();
  scope.filter.keywords = 'test';
  $timeout(function() {
    expect(scope.filtered).toContain(item);
  });
  scope.$apply();
});

我仍然有兴趣知道这种方法是否最好。

3 个答案:

答案 0 :(得分:4)

这是一种糟糕的做法。你应该使用角度特定的去抖动,例如使用$ timeout而不是setTimeout的this。这样,你可以做到

  $timeout.flush();
  expect(scope.filtered).toContain(item);

并且规范将按预期传递。

答案 1 :(得分:1)

我已经用过了:

beforeEach(function() {
    ...
    spyOn(_, 'debounce').and.callFake(function (fn) {
        return function () {
            //stack the function (fn) code out of the current thread execution
            //this would prevent $apply to be invoked inside the $digest
            $timeout(fn);
        };            
    });
});

function digest() {
    //let the $watch be invoked
    scope.$digest();
    //now run the debounced function
    $timeout.flush();
}

it('the test', function() {
    scope.filter.keywords = ...;
    digest();
    expect(...);
});

希望有所帮助

答案 2 :(得分:-1)

使用spyOn替换_.debounce,请检查此链接。 http://gotoanswer.stanford.edu/?q=Jasmine+test+does+not+see+AngularJS+module