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

jasmine, javascript, jquery, settimeout, unit-testing

Solution

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

Problem

I need to write a test for a function that has a `setTimeout()` call inside, but i can't find how i should do. This is the function ``` // Disables all submit buttons after a submit button is pressed. var block_all_submit_and_ajax = function( el ) { // Clone the clicked button, we need to know what button has been clicked so that we can react accordingly var $clone = $( el ).clone(); // Change the type to hidden $clone.attr( 'type', 'hidden' ); // Put the hidden button in the DOM $( el ).after( $clone ); // Disable all submit button. I use setTimeout otherwise this doesn't work in chrome. setTimeout(function() { $( '#facebook input[type=submit]' ).prop( 'disabled', true ); }, 10); // unbind all click handler from ajax $( '#facebook a.btn' ).unbind( "click" ); // Disable all AJAX buttons. $( '#facebook a.btn' ).click( function( e ) { e.preventDefault(); e.stopImmediatePropagation(); } ); }; ``` And this is my test ``` 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) ); // check that all submit are disabled $( '#facebook input[type=submit]' ).each( function( i, el ) { console.log( 'f' ); expect( el ).toHaveProp( 'disabled', true ); } ); } ); ``` I've tried using `jasmine.Clock.useMock();` and `jasmine.Clock.tick(11);` but i couldn't get things to work, the test never pass

Original source