Comment tester une fonction qui a un setTimeout avec du jasmin?

J'ai besoin d'écrire un test pour une fonction qui a un appel setTimeout() , mais je ne peux pas trouver comment je devrais le faire.

C'est la fonction

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

Et c'est mon 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 ); } ); } ); 

J'ai essayé d'utiliser jasmine.Clock.useMock(); Et jasmine.Clock.tick(11); Mais je ne pouvais pas faire fonctionner les choses, le test ne passe jamais

L'approche globale varie en fonction de votre version Jasmine.

Jasmine 1.3

Vous pouvez utiliser 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); }); 

Vous pouvez également utiliser des waits si vous savez exactement combien de temps cela prendra:

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

Il y a aussi une troisième façon de faire cela, sans avoir besoin d' waitsFor , d' waitsFor et d' 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

Vous pouvez utiliser le rappel de test done :

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

Vous pouvez vous moquer du comportement de la minuterie:

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

Je n'ai jamais fait de test avec du jasmin, mais je pense que je comprends votre problème. Je voudrais restructurer le code un peu pour vous permettre d'envelopper la fonction appelée dans une fonction proxy comme ceci:

Modifiez votre code qui est testé pour extraire le code setTimeout dans une autre fonction:

Code original:

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

Code modifié:

 // 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(disableSubmitButtons, 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(); } ); }; var utilityFunctions = { disableSubmitButtons : function() { $( '#facebook input[type=submit]' ).prop( 'disabled', true ); } } 

Ensuite, je modifierais le code de test comme ceci:

 it( "Disable all submit buttons", function() { // Get a button var $button = $( '#ai1ec_subscribe_users' ); var originalFunction = utilityFunctions.disableSubmitButtons; utilityFunctions.disableSubmitButtons = function() { // call the original code, and follow it up with the test originalFunction(); // check that all submit are disabled $( '#facebook input[type=submit]' ).each( function( i, el ) { console.log( 'f' ); expect( el ).toHaveProp( 'disabled', true ); }); // set things back the way they were utilityFunctions.disableSubmitButtons = originalFunction; } // Call the function utility_functions.block_all_submit_and_ajax( $button.get(0) ); }); 

Depuis Jasmine 2, la syntaxe a changé: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support

Vous pouvez maintenant passer simplement un rappel à beforeEach , it and afterEach :

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