Joel's Thoughts

Writing A Testable Javascript Function

July 26, 2016

Writing unit test on our Javascript code is beneficial and a good practice.

Here are the 3 main reasons why:

  1. Testing makes the code flexible or re-usable.
  2. Test helps define clearly what our code is supposed to do.
  3. Testing provides protection against bug or defects.

Let’s consider this javascript function:

function displayAddress () {
    var address = $('#Address-1'),
    parent = address.closest('.form-group.collapse');

    if (address.length > 0 && $.trim(address.val()).length > 0 && parent.length > 0) {
        parent_wrapper.addClass('in');
    }
}

Now, this function is not that testable. Let me break it down.

  1. It is not re-usable or flexible. It totally relies on the existence of hard coded DOM elements.
  2. A bug can be introduced easily. What if someone changed the id from Address-1 to Address-2? Changing the id will totally screw-up the code.
  3. Using the function, we’re not sure what to expect from it if one of the DOM element does not exist.

Rewriting the function to make it testable will result to this:

function displayAddress (address, parent, display_class_name) {    
    var noAddressFound = (0 === address.length || 0 === $.trim(address.val()).length),    
    noParentFound =  (0 === parent.length);

    if (noAddressFound || noParentFound) {
        return false;
    }

    parent.addClass(display_class_name);
    return true;    
}

Now, we have a testable Javascript function.

  1. The code is flexible and re-usable. It does not rely on any hard coded values since the dependencies are injected. This is the whole concept of Dependency Injection.
  2. We can now see clearly what’s going on inside the function. Example, I can confidently say that the function will return true if there’s an address otherwise false.
  3. The code is now protected from bugs/defects since we can easily write a unit test for it.

Using QUnit as a test suite, we can write our unit test like this.


var display_class_name = 'in';

QUnit.test( "Testing the \"displayAddress\" function with set address", function( assert ) {
   var fixture = $( "#qunit-fixture" );
   fixture.append('<div class="form-group collapse"><input id="Address-1" type="text" value="1234 Marine Av. Los Angeles, Ca."></div>');

   var address = $("#Address-1"),
   parent = $(".form-group.collapse");

   //we can expect that our function will return true
   assert.equal(displayAddress(address,parent,display_class_name), true, "Input address is displayed.");
});

QUnit.test( "Testing the \"displayAddress\" function with no set address", function( assert ) {
   var fixture = $( "#qunit-fixture" );
   fixture.append('<div class="form-group collapse"><input id="Address-2" type="text" value=""></div>');

   var address = $("#Address-2"),
   parent = address.parent();

   //we can expect that our function will return false
   assert.equal(displayAddress(address,parent,display_class_name), false, "Input address is not displayed.");
});









  • About
  • Search
  • Resume
  • Powered by Jekyll using the Trio theme