如何使用Jasmine的debounce函数测试AngularJS手表

如何使用Jasmine的debounce函数测试AngularJS手表,angularjs,jasmine,karma-jasmine,Angularjs,Jasmine,Karma Jasmine,我有一个带手表的控制器,它使用lodash的去盎司延迟过滤列表500毫秒 $scope.$watch('filter.keywords', _.debounce(function () { $scope.$apply(function () { $scope.filtered = _.where(list, filter); }); }, 500)); 我试图编写一个Jasmine测试,模拟输入未找到的筛选关键字,然后输入已找到的关键字 我最初的尝试是在为关键字分配了一个新值后

我有一个带手表的控制器,它使用lodash的去盎司延迟过滤列表500毫秒

$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一个大于去盎司500毫秒的值

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);
});
其他人是如何解决这个问题的

EDIT:我找到了一个解决方案,将期望值封装在$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();
});

我仍然有兴趣知道这种方法是否是最好的。这是一种糟糕的方法。您应该使用特定于角度的去抖动,例如使用$timeout而不是setTimeout。那样的话,你可以做到

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();
});
  $timeout.flush();
  expect(scope.filtered).toContain(item);

该规范将按预期通过。

使用spyOn替换uu.debounce,检查此链接

我用过这个:

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(...);
});
希望能有帮助