Jasmine – evento desencadenante no funciona

Código que estoy tratando de probar:

$(".toggle_item").on("change", function() { console.log("change triggered") item_name = $(this).data("name"); value = $(this).prop("checked"); if (Item.isValid(item_name) && cartModule.isUnique(item_name)) { cartModule.toggleItem(item_name, value); } }) 

Especificaciones de jasmine:

 describe("changing toggle item", function() { beforeEach(function() { console.log("in spec") affix(".toggle_item[data-name='ladder']") spyOn(cartModule, "isUnique") spyOn(Item, "isValid") $(".toggle_item").trigger("change") }) it("should check item for validity & cart for uniqueness", function() { expect(Item.isValid).toHaveBeenCalledWith("ladder") expect(cartModule.isUnique).toHaveBeenCalledWith("ladder") }) }) 

La salida del registro de la consola indica que el disparador no se disparó. Salida de registro:

 > "in spec" 

FWIW:

  • He intentado usar tanto loadFixtures como loadFixtures
  • He intentado usar tanto $(".toggle_item").on("change"... y $(".toggle_item").change...

Lista de gems:

 jasmine (2.7.0) jasmine-core (2.8.0, 2.7.0) jasmine-jquery-rails (2.0.3) jasmine-rails (0.14.1) 

** Respuesta actualizada: 2018-02-03 **

El problema fundamental aquí es que su código se está ejecutando demasiado pronto, antes de que se hayan configurado sus dispositivos. Esto es diferente a cargar su código antes de todas sus pruebas. Debe poder controlar cuándo se ejecuta su código una vez que se ha cargado .

Esto tiene más que ver con la forma en que escribe su código para que pueda probarse, y es en gran medida independiente de las herramientas y bibliotecas que realmente se utilizan para las pruebas.

Aquí hay un ejemplo:

 // There is no way to test this expression - it runs as soon as it is loaded 1 + 2 // This is similar to the line above - it tries to add the event listener as soon // as the line of code is encountered. If you haven't set up fixtures before this line is run // then you can't test it. $('.toggle_item').on('change', ...); // Here is an example of code that is testable // It is testable because we have separated out the loading of the code // from the **invocation** of the code. function add(){ // ie This expression will only run when `add()` is invoked. return 1 + 2; } // Here is an example that adds a bit more control over when the event listeners are added. $(function(){ // This expression runs when `$.ready` is fired (aka `DOMContentLoaded`) // If you can delay `$.ready` until your fixtures are set up then this will work. $('.toggle_item').on('change', ...); }) 

La explicación en su respuesta vinculada no es del todo correcta. $('.selector').click(...) es solo un alias o short-hand para $('.selector').on('click', ...) así que cambiar a eso no hará que diferencia – son funcionalmente exactamente iguales.

La razón por la que la respuesta realmente funciona en ese caso es porque el detector de eventos se agrega al evento $.ready() lugar de hacerlo inmediatamente tan pronto como se carga el código.

Es la diferencia entre ejecutar esto:

 console.log('1 before'); console.log('2 middle'); console.log('3 after'); 

Resultado:

 > 1 before > 2 middle > 3 after 

Y ejecutando esto:

 console.log('1 before'); $(function(){ console.log('2 middle'); }); console.log('3 after'); 

Resultado:

 > 1 before > 3 after > 2 middle 

Otra herramienta que podría ayudarlo aquí son los oyentes de eventos delegates .

Básicamente, agrega un único detector de eventos a un elemento más arriba en el árbol DOM que escucha eventos de selectores secundarios particulares.

p.ej:

 $(function(){ $(document).on('change', '.toggle_item', function(){ }); }) 

El beneficio de esto es que el detector de eventos se puede agregar antes, evento antes de que exista .toggle_item , pero los escuchas se activarán una vez que se hayan agregado los elementos.

Hay algunas advertencias sobre el uso de delegates de eventos (por ejemplo, cuando se usa event.preventDefault() o event.stopPropagation() ) pero aún son una herramienta muy útil.


Respuesta original

En su código bajo prueba, ¿puede controlar / retrasar cuando se agrega el detector de eventos?

Sospecho que su código está intentando agregar el detector de eventos a .toggle_item antes de que se .toggle_item la .toggle_item del affix(".toggle_item[data-name='ladder']") en sus pruebas.

 console.log('Adding listener') $(".toggle_item").on("change", function() { console.log("change triggered") ... }); 

Sabrás que está fuera de orden si obtienes:

 > "Adding listener" > "in spec" 

En lugar de lo que queremos:

 > "in spec" > "Adding listener"