Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 379
Nicola Peluchetti Avatar asked Jun 08 '12 19:06

Nicola Peluchetti


2 Answers

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() }); 
like image 70
loganfsmyth Avatar answered Sep 29 '22 04:09

loganfsmyth


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.

like image 29
Dominic Avatar answered Sep 29 '22 03:09

Dominic