Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stub out a jQuery selector call?

Tags:

I'm trying to get better at unit testing my JavaScript. I have the following code:

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

My test runner doesn't have the #category input on the page, so how would I stub/mock out the jQuery selector here? I've looked at both the jasmin and sinon documentation, but can't figure out how to get them to work here, since their stubs operate on objects, which $ is not.

like image 678
swilliams Avatar asked Dec 15 '11 17:12

swilliams


People also ask

What is jQuery selector?

jQuery selectors are used to "find" (or select) HTML elements based on their name, id, classes, types, attributes, values of attributes and much more. It's based on the existing CSS Selectors, and in addition, it has some own custom selectors. All selectors in jQuery start with the dollar sign and parentheses: $().

Which of the following is correct about jQuery selector?

Q 1 - Which of the following is correct about jQuery selector? A - A jQuery Selector is a function which makes use of expressions to find out matching elements from a DOM based on the given criteria.

What is stubbing in Javascript?

What are stubs? While spies wrap existing functionality, stubs allow us to replace the functionality completely. The original function won't run anymore, but rather our new stub that simply returns a result. This is especially handy if we want to test async stuff that makes use of things like jQuery's AJAX methods.


1 Answers

The problem here is that $() is a function that returns an object with the method val(). So you have to stub $() to return a stubbed object having the method val.

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

But the main mistake here is to let the code you want to test call the function $() to create new instances. Why? Its best practice to create no new instances in your class, but to pass them into the constructor. Let's say you have function that will get a value out of an input, double it, and write it back to another:

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

In this case you create 2 new objects by calling $(). Now you have to stub $() to return a mock and a stub. Using the next example you can avoid this:

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

While, in the first case you have to stub $ to return a stub, in the second case you can easily pass a stub and a spy into your function.

So the sinon test for the second one would look like this:

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

So, as you have no dom elements here, you can simply test your application logic with no need to create the same dom as in your app.

like image 190
Andreas Köberle Avatar answered Sep 28 '22 16:09

Andreas Köberle