Testing your JavaScript code.

JavaScript is pretty popular nowadays. There are a variety of JavaScript frameworks for front-end like Angularjs developmentBackbonejs development,  etc.  and a server side technology as well (Nodejs) which has it’s own set of frameworks (Expressjs, Koajs) for ease of development. Since the usage of JavaScript has been increased to a huge extent compared to just a few years back, it also becomes important to make the code more reliable and testable. Whether be it JavaScript or any other language, whether be it front-end or the server, you need to have test cases for your project to make it more reliable and robust.

The popularly known Test Driven Development aka TDD should be followed everywhere. TDD ensures we write bare minimum amount of code that is efficient, reliable and any further changes to our code that still passes our test cases ensures that our code will not break (at least for the test cases we wrote) even if we make huge changes to our codebase.

In this article, we’ll have a look at a test runner that can help test our JavaScript code ( Plain JavaScript code, not dependent on any framework);
Before starting to explore the same, let’s just get down to writing some code. We’ll create a simple function, then keep on adding features to it and then see why writing the same code using TDD would have been much more beneficial.

A simple Add function:

function Add() {
   return 1 + 2;
}

Now let’s just make it return the sum of the arguments the user passes to it.

function Add(a,b) {
   return a + b;
}

Now a new member joins in your development team. He is asked by one of the fellow developers to modify the Add() function and sum up three arguments instead of three:

function Add(a,b,c) {
   return a + b + c;
}

That was simple. He didn’t cared much about passing any default values if the call fails to pass all the three variables assuming that won’t be necessary to do (Not a good thing to do.) Now someone else from your team just pulled in the latest code from the codebase. He then sees that there were lots of commits in the codebase and he just had a glance over it, skipping a few in the middle(even though not beneficial, we generally skip reading few commit message when there are lots of them).

The commit messages were following:

## Developer : Commit Message
#1 Pranay: Update style.css
#2 Pranay: Validate response data.
#3 Siddesh: Add more images for the launch page.
#4 Sagar: Update dependencies and source files.
#5 Pranay: Update add function to accept three arguments.
#6 Siddesh: Update routes.js
#7 Sagar: Add test cases for the login controller.
#8 Pranay: Update bootstrap ………
#9 …..
#10 ……
#11 …..
#12 ……..
#13 ………

Now consider the fact that other developers skipped reading all the comments(specially comment #5) and are completely unaware of the fact that the Add() function now takes three arguments instead of two and there is also no default values provided for the third. This is where the problem starts. Since JavaScript allows the user to invoke functions with the lesser no of arguments then they actually were declared with, there will be no error while invoking the same with the lesser args. Moreover, JavaScript wouldn’t through an exception unless the code is actually executed, since it being a dynamic language.

In our scripts file, we had the following code some where:

var a = document.getElementById('input1').value();
var b = document.getElementById('input2').value();

if(!a || !b) {
   return alert('Please enter both values');
}

var amout = Add(a,b);

$.ajax(url,{data:amount,type:'POST'}).success(function() {
   //invalid response recieved due to invalid data send.
});

Since we didn’t tested our code, we were assuming everything would go green since we are already checking for the existence of both the values we passed as arguments. What we didn’t knew was the CHANGED BEHAVIOUR of our Add() function that would just mess up our entire application execution.

So why weren’t we aware of the changed behavior of our program? Following are the reasons:

1. We didn’t cared about going through all the commit messages and changes.
2. The guy who changed the function declaration didn’t bother to tell others about it assuming he was the only one using it.
3. JavaScript being dynamic language didn’t threw any errors when we executed it with lesser arguments.

Are the above scenarios very rare? No they aren’t. When commits are large, we usually don’t bother to look over each and every commit message. When we change a function that has too small to do and is not used rigorously, we don’t bother to tell everyone about the changes we make. But this only makes our code unstable and error prone.

Now imagine if we would have written test cases for the same. There is a common practice in TDD to run test cases before you commit anything. Running test cases after changes would have failed the test cases and made the developer aware of the consequences of the changes he made. He then would have either gather the whole team to make everyone aware of the changes or add any default values so that the code won’t break. But that would have been possible only when he was aware of those consequences of the changes you make. And that’s what TDD do. It makes you AWARE OF THE CONSEQUENCES of the changes you make in your code.

Even though above example had fairly simple code, it still had chances to break with a little change in it. Consider the real world complex application having thousands and thousands of lines of code. Making sure that our changes won’t break anything becomes much more difficult in a dynamic language like JavaScript. The only solution is to ADD TESTS to your projects. This will always make sure that our changes won’t break the app. (At-least for the test cases we’ve covered)

JavaScript testing frameworks.

JavaScript has a huge variety of the frameworks available to test your code. Following is the list of a few:

1. Jasmine
2. Buster
3. Qunit

In this article we’ll cover testing using Jasmine.

Getting started with Jasmine:

As per the definition on Jasmine’s introduction page:

“Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.”

Jasmine has it’s own set of cool features that makes write test cases fun and easy.

Installing and setting up jasmine. 

Once jasmine is installed, let’s move on to the same function we wrote but now using TDD.

#Test Specs

Let’s just declare our function without defining it’s body:

function Add() {
   //empty function body.
}

Then, we can write our test cases as following:

describe('Add function', function() {
   it('should add two numbers',function() {
      var sum = Add(1,2);
      expect(sum).toEqual(3);
   });
});

executing the above test cases will fail since the add function doesn’t do anything for now. So let’s just add the function body now.

function Add(a,b) {
   return a + b;
}

Running the test case again will pass it. Now let’s modify the function to expect three arguments and return it’s sum.

function Add(a,b,c) {
   return a + b + c;
}

On executing the test case again, we’ll see that our test case no longer passes due to the fact that we are still supplying it two arguments resulting in adding of two variables and one undefined(for the third argument)

This is where we start getting the benefits of our test cases. We instantly get to know impact of the changes we made on the application without even worrying to go through every file and searching for the function invocations.

So looking at the above issue let’s modify our function to pass our existing test case.

The function can be improvised in the following way:

function Add(a,b,c) {
   var c = c || 0; //considering the fact that the first two arguments are provided at all cost;
   return a + b + c;
}

But instead of adding only constant number of arguments, wouldn’t it be better to just loop through the arguments array? Example:

function Add() {
   var sum = 0; //IMP do not forget to initialise it to 0
   for(var i=0;i<arguments.length;i++) {
      sum += arguments[i];
   }
   return sum;
}

and now again run our test case. Hopefully everything goes green now. By doing the above thing we not only managed to keep our code reliable, we also were able to add a new feature of adding variable number of arguments to be passed in the function. We can now add more test cases for our function:
describe(‘Add function’, function() {

it('should add two numbers', function() {
   var sum = Add(1,2);
   expect(sum).toBe(3);
});

it('should add three numbers', function() {
   var sum = add(1,2,3);
   expect(sum).toBe(6);
});

/*
and we keep on adding as many test cases we want
for as many no of arguments we want to invoke
our function with

*/
});

There is no doubt that from the beginning, the function should have been written in such a way that it can accept variable number of arguments and returning the sum of it. But we are not brain-storming  here on how to write better functions. Instead our motto was to be able to understand the importance of TDD in our applications. Now we see that with a little effort, we can make sure that any change we make in the application will not break our entire application by just making sure that our test cases pass.
Thus we see that TDD makes our development more reliable and less error prone. This article was all about testing pure JavaScript code and it’s importance. We’ll also cover testing AngularJS code and many more in the upcoming ones.