How to test a function which has a setTimeout with jasmine? How to test a function which has a setTimeout with jasmine? jquery jquery

How to test a function which has a setTimeout with jasmine?


The overall approach varies based on your Jasmine version.

Jasmine 1.3

You can use waitsFor:

it( "Disable all submit buttons", function() {    // Get a button    var $button = $( '#ai1ec_subscribe_users' );    // Call the function    utility_functions.block_all_submit_and_ajax( $button.get(0) );    // Wait 100ms for all elements to be disabled.    waitsFor('button to be disabled', function(){        var found = true;        // check that all submit are disabled        $( '#facebook input[type=submit]' ).each( function( i, el ) {            if (!el.prop('disabled')) found = false;        });        return found;    }, 100);});

You could also use waits if you know exactly how long it will take:

it( "Disable all submit buttons", function() {    // Get a button    var $button = $( '#ai1ec_subscribe_users' );    // Call the function    utility_functions.block_all_submit_and_ajax( $button.get(0) );    // Wait 20ms before running 'runs' section.    waits(20);    runs(function(){        // check that all submit are disabled        $( '#facebook input[type=submit]' ).each( function( i, el ) {            expect( el ).toHaveProp( 'disabled', true );        });    });});

There is also a third way of doing this, without the need for waits, waitsFor, and runs.

it( "Disable all submit buttons", function() {    jasmine.Clock.useMock();    // Get a button    var $button = $( '#ai1ec_subscribe_users' );    // Call the function    utility_functions.block_all_submit_and_ajax( $button.get(0) );    jasmine.Clock.tick(10);    // check that all submit are disabled    $( '#facebook input[type=submit]' ).each( function( i, el ) {        expect( el ).toHaveProp( 'disabled', true );    });});

Jasmine 2.0

You can use done, the test callback:

it( "Disable all submit buttons", function(done) {    // Get a button    var $button = $( '#ai1ec_subscribe_users' );    utility_functions.block_all_submit_and_ajax( $button.get(0) );    setTimeout(function(){        // check that all submit are disabled        $( '#facebook input[type=submit]' ).each( function( i, el ) {            expect( el ).toHaveProp( 'disabled', true );        });        // Let Jasmine know the test is done.        done();    }, 20);});

you can mock out the timer behavior:

it( "Disable all submit buttons", function() {    jasmine.clock().install();    // Get a button    var $button = $( '#ai1ec_subscribe_users' );    // Call the function    utility_functions.block_all_submit_and_ajax( $button.get(0) );    jasmine.clock().tick(10);    // check that all submit are disabled    $( '#facebook input[type=submit]' ).each( function( i, el ) {        expect( el ).toHaveProp( 'disabled', true );    });    jasmine.clock().uninstall()});


Since Jasmine 2 the syntax has changed: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

You now can simply pass a done callback to beforeEach, it, and afterEach:

it('tests something async', function(done) {    setTimeout(function() {        expect(somethingSlow).toBe(true);        done();    }, 400);});

Update: Since writing this it's now also possible to use async/await which would be my preferred approach.


For anyone googling this, a better answer can be found timer testing

import { fakeAsync, tick, discardPeriodicTasks } from '@angular/core/testing';it('polls statusStore.refreshStatus on an interval', fakeAsync(() => {  spyOn(mockStatusStore, 'refreshStatus').and.callThrough();  component.ngOnInit();  expect(mockStatusStore.refreshStatus).not.toHaveBeenCalled();  tick(3001);  expect(mockStatusStore.refreshStatus).toHaveBeenCalled();  tick(3001);  expect(mockStatusStore.refreshStatus).toHaveBeenCalledTimes(2);  discardPeriodicTasks(); }));