How to test AngularJS watches using debounce function with Jasmine

I have a clock controller that uses debod from lodash to delay filtering the list by 500 ms.

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

I am trying to write a Jasmine test that simulates entering filter keywords that are not found, followed by found keywords.

My initial attempt was to use $ digest after assigning a new value to keywords, which I believe does not work due to failure.

 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); }); 

So I tried to use $ timeout, but that does not work either.

 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); }); 

I also tried to give $ timeout a value in excess of 500 ms set for debounce.

How did others solve this problem?

EDIT: I found a solution that was supposed to wrap the wait in the $ timeout function, then call $ apply in the scope.

 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(); }); 

I'm still curious to know if this approach is the best.

+6
source share
3 answers

This is a bad approach. You should use an angular-specific debounce such as this , which uses $ timeout instead of setTimeout. So you can do

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

and the specification will pass as expected.

+4
source

I used this:

 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(...); }); 

Hope this helps

+1
source

Using spyOn to replace _.debounce, check out this link. http://gotoanswer.stanford.edu/?q=Jasmine+test+does+not+see+AngularJS+module

-1
source

Source: https://habr.com/ru/post/970706/


All Articles