Espionnage sur JQuery Selectors dans Jasmine
-
26-10-2019 - |
Question
Je suis unité de tester un peu de JavaScript avec Jasmine et je souhaite espionner (maquette) un élément du DOM qui est accessible par un sélecteur jQuery.
Ma spécification est:
it("should be able to mock DOM call", function() {
spyOn($("#Something"), 'val').andReturn("bar");
result = $("#Something").val();
expect(result).toEqual("bar");
});
Dans mon specrunner.html je:
<input type="hidden" id="Something" value="foo" />
Malheureusement, la spécification échoue avec:
devrait être en mesure d'appel DOM maquette attendu 'foo' à égale 'bar'.
La solution
Cette ligne est erroné:
spyOn($("#Something"), 'val').andReturn("bar");
La fonction spyOn Jasmine attend deux paramètres. Le premier est un objet existant. Le second est un nom de fonction en tant que chaîne. Vous passez correctement dans le nom de la fonction comme une chaîne ( « val ») mais vous n'êtes pas de passage dans un objet existant comme premier paramètre.
$("#Something")
... n'est pas un objet existant. Elle est le résultat (la valeur de retour) d'un sélecteur jQuery. Plus précisément, elle retourne un objet jQuery représentant les noeuds appariés -. Un peu comme un tableau de résultats
$
... est un objet existant.
$.fn
... est un objet existant.
$("#Something")
... pas un objet existant -. Il est le résultat d'un sélecteur jQuery
Cela fonctionne:
it("should be able to mock DOM call", function () {
//spyOn($.fn, "val").andReturn("bar"); //pre-jasmine 2.0 syntax
spyOn($.fn, "val").and.returnValue("bar"); //Jasmine 2.0 Syntax
var result = $("#Something").val();
expect(result).toEqual("bar");
});
Autres conseils
On dirait que j'ai trouvé une bonne solution
it "should open past statuses", ->
# We can't use $('.past') here cause each time $('.past') called it returns different objects
# so we need to store spy in variable
showSpy = spyOn($.fn, 'show')
# do the stuff
$('.show-past').click()
# then check if 'show' action was called
expect($.fn.show).toHaveBeenCalled()
# and if it realy our object
expect(showSpy.mostRecentCall.object.selector).toEqual('.past')
Ce ne repose pas sur votre code, mais j'espère que ce quelqu'un peut aide. Et, oui, par exemple dans coffeescript.
Le problème est que les deux appels à $ retour deux nœuds enveloppés de jQuery différents.
Cela devrait fonctionner:
it("should be able to mock DOM call", function(){
// var node = $("Something");
// spyOn(node, 'val').andReturn('bar');
// expect(node.val()).toEqual('bar');
var node = $("Something");
spyOn(node, 'val').and.returnValue('bar');
expect(node.val()).toEqual('bar');
});
La prochaine fois, l'aide est plus répandue sur la liste de diffusion Jasmine:. Jasmine-js@googlegroups.com
Vous pouvez créer votre propre élément DOM faux et puis utilisez $ ( '# elementid') [0] comme d'habitude
addFakeElementWithId = function (elementId) {
var fake = document.createElement("div");
fake.setAttribute("id", elementId);
document.body.appendChild(fake);
};
I wrote a helper-function, which accepts an array of id/value-pairs.
var jasminTestHelper = {
spyOnValAndFake : function(obj) {
var i, j;
spyOn($.fn, 'val').andCallFake(function() {
for ( i = 0, j = obj.length; i < j; i++) {
if (this.selector === '#' + obj[i][0]) {
return obj[i][1];
}
}
})
}
}
Each pair tells the faker-function for which id, which value should be returned if the jQuery-val()-function is called with the id-selector. It is used like this:
jasminTestHelper.spyOnValAndFake([["id1", "value1"], ["id2", "value2"]]);
If $('#id1').val()
is called in your function under test, the fake-function returns value1
, if $('#id2').val()
is called it returns value2
. So you don't need to fiddle with the DOM, you just mock the jQuery-val()-function and simulate return-values. Other jQuery-functions could probably mocked the same way.
I think there is a change in my jasmine version (2.0.3), hence the solution by Alex York didn't work as is, but definitely gave me a path. So here is the working spec jquery code which is to be tested
$('someSelector').data('someAttribute').enable();
here is the jasmine spec part of it
var mockJqueryObject = { enable:function(){},disable:function(){}};
//this mocks the .data('someAttribute') in above code.
spyOn($.fn, "data").and.returnValue(mockSelectBoxObject);
A more granular spec could use another level of mock as
spyOn(mockJqueryObject,"enable")
spyOn(mockJqueryObject,"disable")