How to unit test / mock $ timeout call?

How do I make fun of a timeout call here?

$scope.submitRequest = function () {

    var formData = getData();

    $scope.form = JSON.parse(formData);

    $timeout(function () {
        $('#submitForm').click();            
    }, 2000);

};

I want the timeout to be called with the correct function.

I need an example function spyon mocking $ timeout.

spyOn(someObject,'$timeout')
+4
source share
6 answers

First of all, DOM manipulation should only be done in directives. Also, it is better to use angular.element (...) than $ (...). Finally, to do this, you can expose your item click handler in the area, spy on it and check if this handler is called:

$timeout.flush(2000);
$timeout.verifyNoPendingTasks();
expect(scope.myClickHandler).toHaveBeenCalled();

EDIT:

since the form is not an ng-click handler, you can use the ng-submit handler or add a name to your form and do:

$timeout.flush(2000);
$timeout.verifyNoPendingTasks();
expect(scope.formName.$submitted).toBeTruthy();
+5
source

$timeout , :

beforeEach(module('app', ($provide) => {
  $provide.decorator('$timeout', ($delegate) => {
    var timeoutSpy = jasmine.createSpy().and.returnValue($delegate);
    // methods aren't copied automatically to spy
    return angular.extend(timeoutSpy, $delegate);
  });
}));

, , $timeout . scope/controller:

$scope.submitFormHandler = function () {
    $('#submitForm').click();            
};

...
$timeout($scope.submitFormHandler, 2000);

$timeout:

$timeout.and.stub(); // in case we want to test submitFormHandler separately
scope.submitRequest();
expect($timeout).toHaveBeenCalledWith(scope.submitFormHandler, 2000);

$scope.submitFormHandler .

, jQuery DOM ( , jQuery AngularJS, ). , /mock jQuery API, .

$(...) :

var init = jQuery.prototype.init.bind(jQuery.prototype);
spyOn(jQuery.prototype, 'init').and.callFake(init);

:

var clickSpy = jasmine.createSpy('click');
spyOn(jQuery.prototype, 'init').and.returnValue({ click: clickSpy });

, , mocked jQuery click.

$(...) , #submitForm DOM, unit test.

+4

mock $timeout:

var f = () => {} 
var myTimeoutProviderMock = () => f;

:

beforeEach(angular.mock.module('myModule', ($provide) => {
  $provide.factory('$timeout', myTimeoutProviderMock);
}))

:

spyOn(f);
expect(f).toHaveBeenCalled();

P.S. -.

+1

, $$, $timeout. - :

var timeoutStub = sinon.stub();
var myController = $controller('controllerName', timeoutStub);
$scope.submitRequest();
expect(timeoutStub).to.have.been.called;
+1

- Tesitng $

$timeout, $timeout.flush()

describe('controller: myController', function(){
describe('showAlert', function(){
    beforeEach(function(){
        // Arrange
        vm.alertVisible = false;

        // Act
        vm.showAlert('test alert message');
    });

    it('should show the alert', function(){
        // Assert
        assert.isTrue(vm.alertVisible);
    });

    it('should hide the alert after 5 seconds', function(){
        // Act - flush $timeout queue to fire off deferred function
        $timeout.flush();

        // Assert
        assert.isFalse(vm.alertVisible);
    });
  })
});

Please check out this link http://jasonwatmore.com/post/2015/03/06/angularjs-unit-testing-code-that-uses-timeout

+1
source

I completely agree with the answer of Frane Poljak . You must definitely follow his path. The second way to do this is to taunt $ timeout, as shown below:

describe('MainController', function() {
var $scope, $timeout;

beforeEach(module('app'));

beforeEach(inject(function($rootScope, $controller, $injector) {
  $scope = $rootScope.$new();
  $timeout = jasmine.createSpy('$timeout');
  $controller('MainController', {
    $scope: $scope,
    $timeout: $timeout
  });
}));

it('should submit request, function() {
  $scope.submitRequest();
  expect($timeout).toHaveBeenCalled();
});

Here is a plunker that has both approaches: http://plnkr.co/edit/s5ls11

+1
source

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


All Articles