2012-06-18 8 views
5

Antecedentes:Cómo probar la unidad código JavaScript que interactúa con los elementos DOM

Vengo de Java, por lo que no estoy muy familiarizado con Javascript.

Estamos planeando introducir las pruebas de unidad de JavaScript tanto para nuestro código existente (heredado) como para el trabajo futuro. Somos una tienda de java (primavera, weblogic, etc.) principalmente.

Estamos buscando opciones que nos brinden una buena integración con IDE (idea IntelliJ) y sonar, además de ser capaces de ejecutarlas como parte de una integración continua.

JsTestDriver parece marcar todas las casillas.

Pregunta:

Una gran parte de nuestro código javascript existente es a) embebido dentro de JSP y b) utiliza jQuery para interactuar con los elementos de la página directamente.

¿Cómo podemos hacer para probar una función que depende en gran medida del DOM? He aquí algunos ejemplos de código de funciones que las que estoy hablando:

function enableOccupationDetailsText(){ 
    $("#fldOccupation").val("Unknown"); 
    $("#fldOccupation_Details").attr("disabled", ""); 
    $("#fldOccupation_Details").val(""); 
    $("#fldOccupation_Details").focus(); 
} 

o

jQuery(document).ready(function(){ 

    var oTable = $('#policies').dataTable({ 
      "sDom" : 'frplitip', 
       "bProcessing": true, 
       "bServerSide": true, 
       "sAjaxSource": "xxxx.do", 
       "sPaginationType": "full_numbers", 
       "aaSorting": [[ 1, "asc" ]], 
       "oLanguage": { 
        "sProcessing": "Processing...", 
        "sLengthMenu": "Show _MENU_ policies", 
        "sZeroRecords": "No matching policies found", 
        "sInfo":   "Showing _START_ to _END_ of _TOTAL_ policies", 
        "sInfoEmpty": "Showing 0 to 0 of 0 policies", 
        "sInfoFiltered": "(filtered from _MAX_ total policies)", 
        "sInfoPostFix": "", 
        "sSearch":  "Search:", 
        "sUrl":   "", 
        "oPaginate": { 
         "sFirst": "First", 
         "sPrevious": "Previous", 
         "sNext":  "Next", 
         "sLast":  "Last" 
       } 
      }, 
       "fnRowCallback": function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { 
         $('td:eq(0)', nRow).html("<a href='/ole/policy/general_details.do?policy_id="+aData[0]+"'>"+aData[0]+"</a>"); 
         return nRow; 

       }, 

       "fnServerData" : function (url, data, callback, settings) { 

       settings.jqXHR = $.ajax({ 
        "url": url, 
        "data": data, 
        "success": function (json) { 
         if (json.errorMessage != null) { 
          var an = settings.aanFeatures.r; 
          an[0].style.fontSize="18px"; 
          an[0].style.backgroundColor="red"; 
          an[0].style.height="70px"; 
          an[0].innerHTML=json.errorMessage; 
          setTimeout('window.location="/xxxx"',1000); 
          //window.location="/xxxxx"; 
         } else { 
          $(settings.oInstance).trigger('xhr', settings); 
          callback(json); 
         } 
        }, 
        "dataType": "json", 
        "cache": false, 
        "error": function (xhr, error, thrown) { 
         if (error == "parsererror") { 
          alert("Unexpected error, please contact system administrator. Press OK to be redirected to home page."); 
          window.location="/xxxx"; 
         } 
        } 
       }); 
       } 

      }); 
     $("#policies_filter :text").attr('id', 'fldKeywordSearch'); 
     $("#policies_length :input").attr('id', 'fldNumberOfRows'); 
     $("body").find("span > span").css("border","3px solid red"); 
     oTable.fnSetFilteringDelay(500); 
     oTable.fnSearchHighlighting(); 
     $("#fldKeywordSearch").focus(); 

} 
); 

En este último caso, mi enfoque sería que la función en cuestión es demasiado grande y debe ser roto a menor (unidades) para que pueda ser probado. Pero todos los puntos de interacción con DOM, jQuery, datatables, ajax, etc. hacen que sea realmente complicado refaccionar las cosas de la manera que lo hacemos en el mundo de Java para que sea más comprobable.

Por lo tanto, cualquier sugerencia para los casos anteriores a la muestra sería muy apreciada!

+2

ver también [Pruebas de la manipulación de DOM en la prueba de jazmín] (http://stackoverflow.com/questions/7672389/testing-dom-manipulating-in-jasmine-test) –

+0

También puedes ver PhantomJS webkit sin cabeza – obimod

Respuesta

6

Para probar el siguiente código:

function enableOccupationDetailsText(){ 
    $("#fldOccupation").val("Unknown"); 
    $("#fldOccupation_Details").attr("disabled", ""); 
    $("#fldOccupation_Details").val(""); 
    $("#fldOccupation_Details").focus(); 
} 

podría utilizar el siguiente código:

// First, create the elements 
$('<input>', { id: 'fldOccupation' }).appendTo(document.body); 
$('<input>', { disabled: true, id: 'fldOccupation_Details' }) 
    .appendTo(document.body); 

// Then, run the function to test 
enableOccupationDetailsText(); 

// And test 
assert($('#fldOccupation').val(), 'Unknown'); 
assert($('#fldOccupation_Details').prop('disabled'), false); 

Como ve, es simplemente el clásico setup > run > assert patrón.

+0

¿qué pasa con derribando esos objetos DOM para que no tengas una prueba que interfiera con otra? ¿Sería eso una buena práctica? ¿Si es así, cómo? –

+2

@GregWoods bien, puedes eliminarlos con algo como '$ ('# fldOccupation'). Remove(); $ ('# fldOccupation_Details'). remove(); 'o simplemente' $ (document.body.children) .remove(); ' –

4

quizá selenio/SeleniumGrid es útil para usted: http://seleniumhq.org/

No es un "unittest" por definición, pero se puede escribir pruebas de selenio con Java o Python (y muchos más ...) como las pruebas unitarias. Seleniumtests comienza las pruebas web en navegadores reales, y es muy bueno para pruebas de interfaces (y dom manipulaciones).

Editar: hoy me encontré con este sitio que describe diferentes maneras para pruebas unitarias especialmente en un fondo jQuery: http://addyosmani.com/blog/jquery-testing-tools/

Cuestiones relacionadas