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