Unit Testing Javascript

Recently the project I’ve been working on has been moving more and more towards client side javascript, especially using jQuery. We have been pretty consistent on the server side, especially in our business logic, in creating unit tests. We have over 1,000 unit tests in our business tier leveraging nUnit and Rhino Mocks, that are run every time a check in is done using Cruise Control for continuous integration. Pretty standard stuff for server side logic.

Since we are using more and more javascript why not reap the quality benefits of good unit test coverage here as well?  Considering javascript is non-typed and allows the running of strings as code through the ‘eval’ function it would seem even more important to have good unit test coverage of our javascript.  Up to now we’ve ignored it since it’s been considered UI and not really logic.  With more and more ajax integration this no longer seems like a good practice.

For jQuery driven functionality we have been using the jQuery $.ajax method to call down to asp.net pagemethods located  in web forms we created to support the jQuery functionality.   ASP.net pagemethods are essentially webservice calls located in a webform.  The calls have to be static and must be decorated with the [Webmethod] attribute.   Here is a great blog post going into great detail about exactly how to call an ASP.net pagemethod from jQuery.  We essentially are doing the same thing.  We’ve actually wrapped our $.ajax call so we can centralize error handling and abstract away the ‘.d’ return value you get when the pagemethod does it’s json serialization.

This post is about testing, however, so enough with how we’re using jQuery ajax.   From a testing perspetive what we wanted to be able to do was achieve the same test coverage in our jQuery and javascript as we have on our server side logic.   A little googling and what did I find, but qUnit!  The motif is almost the same as writing tests for nUnit, and when you run your tests qUnit provides default css so test results are shown in a html page in a very similar manner to how the nUnit client shows it’s test results.

The great thing is how easy this is to accomplish.  All you need to do is write tests in a .js file that exercise the code you wish to test using the qUnit syntax.  Then in a html page include jQuery, qUnit, the code you are testing and your test code.  In the html provide the nodes that qUnit will want to write to and, you’re done.   Here’s a very simple html example:

<html xmlns="http://www.w3.org/1999/xhtml" >
   <head>
      <title>QUnit Test Example</title>
        <!-- css from qUnit to make output look good -->
          <link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen">
     <!-- jQuery and qUnit include -->
       <script type="text/javascript" src="/scripts/jquery-1.4.1.js" ></script>
       <script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
        <!-- javascript you are testing include -->
       <script type="text/javascript" src="/scripts/ControlScript.js"></script>
        <!-- tests you wrote include -->
       <script type="text/javascript" src="/scripts/ControlScriptTests.js"></script>
   </head>
  <!-- nodes qUnit will write to -->
   <body>
       <h1 id="qunit-header">QUnit Test Suite</h1>
       <h2 id="qunit-banner"></h2>
       <div id="qunit-testrunner-toolbar"></div>
       <h2 id="qunit-userAgent"></h2>
       <ol id="qunit-tests"></ol>
   </body>
   </html>

Very code I’m testing:

[javascript]
function SetupButton(buttonID, txtBoxID, displayText)
{
$("#" + buttonID).click(function() {
$("#" + txtBoxID).attr("value", $("#" + txtBoxID).attr("value") + ‘ ‘ + displayText);

});
}
[/javascript]

And here are the tests I’m running:

[javascript]
test("SetupButtonTest()", function() {

var btn = document.createElement("input");
btn.id = "btn";

btn.type = "button";
document.appendChild(btn);

var txt = document.createElement("input");
txt.id = "txt";
txt.type = "text";
document.appendChild(txt);

SetupButton("btn", "txt", "disp");
$("#btn").click();
equals($("#txt").attr("value"), " disp", "text box has display value: " + $("#txt").attr("value"));

})

test("SetupButtonTest2()", function() {

var btn = document.createElement("input");
btn.id = "btn";

btn.type = "button";
document.appendChild(btn);

var txt = document.createElement("input");
txt.id = "txt";
txt.type = "text";
document.appendChild(txt);

SetupButton("btn", "txt", "disp");
$("#btn").click();
equals($("#txt").attr("value"), "disp", "text box has display value: " + $("#txt").attr("value"));

})
[/javascript]

As you can see qUnit provides a pretty straightforward way to unit test the now more complex javascript we’re writing in our project (the above is just an example, not actual code from our project). The next step is to integrate qUnit into our continuous integration. We would like to have our javascript tests run with every check in, just like our server side tests do. Here is a post on how to do it, it’s seems a little complicated. I will give it a try and put up a post as to the results.

Hopefully we will be able to bring the benefites of good unit testing coverage out from just our server code and now apply it to the more and more complex client side code we’re creating.  After all why would it not be good practice to test code just because it’s javascript?  It seems even more important to test in a language that is non-typed and allows run-time execution of strings as code.