2012-10-03 15 views
15

Estoy bastante seguro de que el problema es que los enlaces de jquery configurados para ejecutarse en $ (documento) .ready no tienen disponible el accesorio html. Entonces, cuando ocurren mis eventos que están destinados a realizar un cambio en el DOM a través de una función jquery, no ocurre nada y mis pruebas fallan. Vi una "solución" a este problema here, pero esa solución que me funcionó, requería cambiar mi función de jquery para enlazar con el método .live en lugar del método .click. Tengo dos problemas con esto. Primero, no quiero tener que cambiar mi código de trabajo para que las pruebas pasen correctamente. El marco de prueba debe probar si el código funcionará en la aplicación, donde la carga DOM y los enlaces javascript ocurren en el orden correcto. El segundo problema que tengo con la solución es que .on y .delegate no funcionaron por alguna razón y lo único que terminó funcionando fue usar el método .live, que actualmente está en proceso de desaprobación. En conclusión, me gustaría descubrir cómo cambiar mis pruebas o el propio marco de prueba, de modo que los dispositivos se carguen antes de que las funciones que se ejecutan en $ (documento) .ready.¿Cómo puedo cargar los dispositivos de prueba de jazmín antes de que javascript considere que el documento está "listo"?

Estoy trabajando con Rails 3.2.8 y tengo dos ramas diferentes configuradas para experimentar con las pruebas de jazmín. Una de las ramas usa la gema jasminerice y la otra usa la gema jasmine-rails. Las pruebas de JavaScript y jQuery (cuando se usa el método .live) pasan todas correctamente en ambas configuraciones.

Aquí es una descripción de la rama usando arroz jazmín:

Aquí están las líneas de mi archivo Gemfile.lock que describen el jazmín y jQuery set-up:

jasminerice (0.0.9) 
    coffee-rails 
    haml 
jquery-rails (2.1.3) 
    railties (>= 3.1.0, < 5.0) 
    thor (~> 0.14) 

arroz jazmín incluye la extensión por jasmine-jquery defecto. La extensión jasmine-jQuery proporciona el método toHaveText que estoy usando en las pruebas.

Los jasmine_jquery_test.js archivo de prueba que se encuentra directamente en el directorio spec/javascript contiene este contenido:

#= require application 

describe ("my basic jasmine jquery test", function(){ 

    beforeEach(function(){ 
     $('<a id="test_link" href="somewhere.html">My test link</a>').appendTo('body'); 
    }); 

    afterEach(function(){ 
     $('a#test_link').remove(); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does some the same basic jQuery thing with a different trigger type", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 
describe ('subtraction', function(){ 

    var a = 1; 
    var b = 2; 

    it("returns the correct answer", function(){ 
     expect(subtraction(a,b)).toBe(-1); 
    }); 

}); 

Mis tests.js archivo JavaScript que se encuentra en el directorio app/activos/javascript tiene este contenido:

function subtraction(a,b){ 
    return a - b; 
} 

jQuery (function($) { 
/* 
    The function I would rather use - 
    $("a#test_link").click(changeTheTextOfTheLink) 
    function changeTheTextOfTheLink(e) { 
     e.preventDefault() 
     $("a#test_link").append(' is now longer'); 
    } 
*/ 

    $("a#test_link").live('click', function(e) { 
     e.preventDefault(); 
     $("a#test_link").append(' is now longer'); 
    }); 

}); 

Mi archivo application.js ubicado en la misma app/activos/javascript dir tiene este contenido:

//= require jquery 
//= require jquery_ujs 
//= require bootstrap 
//= require vendor 
//= require_tree . 

Y la descripción de la rama jazmines-rieles se puede encontrar en el contenido de mi first jasmine test related stackoverflow question.

Así que si alguien tiene una idea de cómo manipular las pruebas de manera que las funciones $ (documento) .ready se ejecuten después de que se carguen los dispositivos, me gustaría mucho escuchar sus ideas.

Respuesta

6

Agregar el jQuery directamente al accesorio html funcionó para que obtuviera el comportamiento deseado. No es exactamente una respuesta a esta pregunta, pero estoy empezando a creer que es la mejor solución disponible actualmente. Mis cambios se realizaron en la configuración de gemas de jazmines y todavía no lo he probado en la rama jasminerice.

Aquí está mi archivo de prueba:

describe ("my basic jasmine jquery test", function(){ 

    beforeEach(function(){ 
     loadFixtures('myfixture.html'); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does the same basic jQuery thing with a different event initiation method", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 
describe ('substraction', function(){ 

    var a = 1; 
    var b = 2; 

    it("returns the correct answer", function(){ 
     expect(substraction(a,b)).toBe(-1); 
    }); 

}); 

Y aquí está mi archivo de datos:

<a id="test_link" href="somewhere.html">My test link</a> 

<script> 
    $("a#test_link").click(changeTheTextOfTheLink) 
    function changeTheTextOfTheLink(e) { 
     e.preventDefault() 
     $("a#test_link").append(' is now longer'); 
    } 
</script> 
+1

Como se indica en la documentación [jasmine-jquery] (https://github.com/velesin/jasmine-jquery) 'De manera predeterminada, los dispositivos se cargan desde spec/javascripts/fixtures. Puede configurar esta ruta: jasmine.getFixtures(). FixturesPath = 'my/new/path'; ' – RamRovi

+0

¿Sigue siendo esta la mejor solución? a su entender, esto es molesto porque ahora, cada vez que cambia el código de producción, ¡tiene que copiarlo al accesorio! – james

1

Personalmente, considero que se trata de un error jazmín-jquery. "Lo resolví" haciendo que mis accesorios formen parte de SpecRunner.html. No es ideal, pero funciona en casos simples.

+2

¿Estás usando Jasmine con una aplicación de Rails? Si es así, ¿podrías explicar tu configuración? Básicamente, que yo sepa, no estoy usando un archivo SpecRunner.html. Pero posiblemente agregar las funciones jQuery a mis dispositivos funcionará de la misma manera ... lo intentaré. –

1

¿Ha tratado de jazmín-jQuery?

https://github.com/velesin/jasmine-jquery

desde su página de GitHub,

jazmín-jQuery ofrece dos extensiones para Jasmine Framework de Pruebas JavaScript:

un conjunto de comparadores personalizados para framework jQuery una API para el manejo de HTML , CSS y JSON en sus especificaciones

1

I u sed dom_munger para generar automáticamente el accesorio para mí, por lo que agregar el código jquery manualmente dentro del dispositivo no es una opción para mí. He estado buscando la misma respuesta, y la mejor solución que puedo pensar ahora es usar delegado de evento en jQuery.

Por ejemplo, en lugar de escribir esto:

$('#target').click(function(){ 
    // Do work 
}); 

hacer esto:

$(document).on('click', '#target', function(){ 
    // Do work 
}); 

De esta manera, el oyente está unido al documento, que está presente antes de que se carga el accesorio. Entonces, cuando el evento de clic ocurre en #objetivo, se dispara para documentar. El documento verifica si el origen coincide con el segundo argumento - '#target'. Si coincide, se llamará a la función del controlador.

Sé que hay limitaciones en esto, como la inicialización de complementos, pero resuelve parte del problema.

+0

No escala, pesadilla de rendimiento. Está dejando que su marco de prueba afecte negativamente a su código. – sarink

+0

pesadilla de rendimiento? ¿Qué tal si hacemos $ ("# parent-of-target") on ("click", "#target", function() {}); –

1

Tomé un enfoque ligeramente diferente a los que se describen aquí para resolver esta limitación.

Descargo de responsabilidad: Trabajo para Microsoft, así que no puedo publicar mi código fuente aquí sin la aprobación legal, así que en su lugar solo describiré un enfoque que funciona bien.

lugar de tratar de cambiar la forma en document.ready obras, que modifican la fuente de jazmín-jquery para apoyar una función llamada fixturesReady que tiene una devolución de llamada.

Esencialmente esto se define dentro de un IIFE, y contiene una matriz de devoluciones de llamadas por nombre de evento en privado, que se repiten en el desencadenador.

Luego en este fragmento se puede poner el gatillo:

jasmine.Fixtures.prototype.load = function() { 
    this.cleanUp() 
    this.createContainer_(this.read.apply(this, arguments)) 

    fixturesReady.trigger("loaded", arguments); // <----- ADD THIS 

} 

Así que en sus pruebas ahora se puede codificar en contra:

fixturesReady(yourCallback) 

Y usted sabe que cuando yourCallback se invoca usted puede de manera segura consulta el DOM para tus elementos de fijación.

Además, si estás usando el plugin de jazmín async.beforeEach usted puede hacer esto:

async.beforeEach(function(done){ 

    fixturesReady(done); 

    ... 

    loadFixtures("...."); 

}); 

Espero que ayude, y sirve para darle algunas ideas sobre la solución de este problema.

NOTA: Recuerde que en su plugin para borrar cualquier devoluciones de llamada en un bloque de afterEach si es necesario :)

1

Ha sido un tiempo desde que se hizo esta pregunta (y una respuesta aceptada).

Este es un mejor enfoque para estructurar su prueba y cargar el script para probarlo con jazmín.

plantillas/link.tmpl.html

<a id="test_link" href="somewhere.html">My test link</a> 

JS/TEST-link.js

$("a#test_link").click(changeTheTextOfTheLink) 
function changeTheTextOfTheLink(e) { 
    e.preventDefault() 
    $("a#test_link").append(' is now longer'); 
} 

espec/LINK-test.spec.js

describe ("my basic jasmine jquery test", function(){ 

    jasmine.getFixtures().fixturesPath = '' 

    var loadScript = function(path) { 
     appendSetFixtures('<script src="' + path + '"></script>'); 
    }; 

    beforeEach(function(){ 
     loadFixtures('templates/link.tmpl.html'); 
     loadScript('js/test-link.js'); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does the same basic jQuery thing with a different event initiation method", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 

Spec Runner

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
    <title>Spec Runner</title> 

    <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.3/jasmine.css"> 
    <script type="text/javascript" src="lib/jasmine-2.0.3/jasmine.js"></script> 
    <script type="text/javascript" src="lib/jasmine-2.0.3/jasmine-html.js"></script> 
    <script src="lib/jasmine-2.2/boot.js"></script> 

    <script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script> 
    <script type="text/javascript" src="lib/jasmine-jquery.js"></script> 

    <script type="text/javascript" src="specs/link-test.spec.js"></script> 
</head> 

<body> 
</body> 
</html> 
Cuestiones relacionadas