¿Suprimir una llamada al selector jQuery?

Estoy tratando de mejorar en la testing unitaria de mi JavaScript. Tengo el siguiente código:

var categoryVal = $('#category').val(); if (categoryVal === '') { doSomething(); } 

Mi cornetworkingor de testing no tiene la input #category en la página, así que, ¿cómo podría cortar / simular el selector jQuery aquí? He analizado tanto la documentation de jasmin como la de sinon , pero no puedo entender cómo hacer que funcionen aquí, ya que sus códigos funcionan en objects, lo que no es $ .

El problema aquí es que $() es una function que devuelve un object con el método val() . Por lo tanto, debe anotar $ () para devolver un object trozado que tenga el método val.

 $ = sinon.stub(); $.withArgs('#category').returns(sinon.stub({val: function(){}})); 

Pero el principal error aquí es dejar que el código que desea probar llame a la function $ () para crear nuevas instancias. ¿Por qué? Su mejor práctica es no crear nuevas instancias en su class, sino pasarlas al constructor. Supongamos que tiene una function que obtendrá un valor de una input, la duplicará y la volverá a escribir en otra:

 function doubleIt(){ $('#el2').val(('#el1').val() *2); } 

En este caso, crea 2 objects nuevos llamando a $() . Ahora tiene que anotar $() para devolver un simulacro y un talón. Usando el siguiente ejemplo puedes evitar esto:

 function doubleIt(el1, el2){ el2.val(el1.val() *2); } 

Mientras que, en el primer caso, tiene que pagar $ para devolver un talón, en el segundo caso puede pasar fácilmente un talón y un espía a su function.

Entonces la testing de sinon para el segundo se vería así:

 var el1 = sinon.stub({val: function(){}}); el1.returns(2); var el2 = sinon.spy({val: function(){}}, 'val') doubleIt(el1, el2) assert(el2.withArgs(4).calledOnce) 

Entonces, como no tiene elementos dom aquí, simplemente puede probar la lógica de su aplicación sin necesidad de crear el mismo dominio que en su aplicación.

jQuery usa el motor selector Css Sizzle debajo del capó y está desacoplado por lo que solo hay unos pocos lugares donde se engancha. Puedes interceptar esto para evitar cualquier interacción con el dom.

jQuery.find es el más importante para modificar y responder con lo que quieras. Sinon podría usarse aquí o intercambiar temporalmente la function.

p.ej

 existingEngine = jQuery.find jQuery.find = function(selector){ console.log(selector) } $(".test") //>> ".test" jQuery.find = existingEngine 

también podría aplicar una condición de captura específica con una reserva

 existingEngine = jQuery.find jQuery.find = function(selector){ if(selector=='blah'}{ return "test"; } return existingEngine.find.apply(existingEngine, arguments) } 

En mi trabajo reciente, he creado un object ficticio que responde como un nodo dom y lo envuelve en un object jQuery. Esto responderá a val () correctamente y tendrá todos los methods jquery presentes que espera. En mi caso, simplemente estoy extrayendo valores de una forma. Si está haciendo una manipulación real, es posible que necesite ser más inteligente que esto, tal vez creando un nodo dom temporal con jQuery que represente lo que esperaba.

 obj = { value: "blah", type: "text", nodeName: "input", } $(obj).val(); // "blah" 

Aquí hay una guía bastante buena para probar tus vistas si estás utilizando Backbone.js y Jasmin. Desplázate hacia abajo a la sección Ver.

http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html

Es cierto, los stubs operan en objects. Supongo que el objective de crear un talón de vista así.

 this.todoViewStub = sinon.stub(window, "TodoView") .returns(this.todoView); 

Es solo para poder renderizar la vista más tarde.

 this.view.render(); 

En otras palabras, agregue el div '#category' al DOM del testrunner, para que $ pueda actuar sobre él. Si su div '#category' no está en this.view, entonces probablemente solo pueda crear una página test.html en la que ejecute su testing aislada. Este es un patrón común en el marco de JavaScript MVC que estoy más acostumbrado a ese Backbone.

Aquí hay un ejemplo de estructura de aplicación JMVC simple:

 /todo /models todo.js /list /views init.tmpl listItem.tmpl list.css list.js (Controller) unitTest.js (Tests for your list.) list_test.html (A html for your unit tests to run on.) 

Con esta configuration, puede include el div "#category" en su list_test.html si no lo tiene ya dentro de una de las vistas.