Are you unit testing your javascript code? There are numerous javascript unit testing frameworks out in the wild; JsUnit, rhinounit, QUnit, YUI’s Yeti, js-test-driver, etc. In fact, here is a stackoverflow thread listing all of these and more. I’ve recently used QUnit which is a framework written on top of, and maintained by the folks over at jQuery.

In order to use QUnit to test your javascript code, you create a single html page to house your tests. In the header of your page, you link to the jQuery script file, a QUnit script file, and a QUnit stylesheet. In the body of your html page, you insert the following markup, which will be used by QUnit as a console to output the results of your tests.

    <h1 id="qunit-header">Your Test Header</h1>
    <h2 id="qunit-banner"></h2>
    <div id="qunit-testrunner-toolbar"></div>
    <h2 id="qunit-userAgent"></h2>
    <ol id="qunit-tests"></ol>
    <div id="qunit-fixture"></div>

Once these things are in place, you can begin writing unit tests for your javascript. To do this, QUnit provides a function called “test” which takes a string parameter that acts as the name of the test in the results, and a function parameter, which is just an anonymous function containing assertion type function calls to other QUnit functions. The details of the test function can be found on QUnits site. Let’s say you were writing a math library, and decided to include an “add” function. A simple test for this function would look like:

test("addition tests", function () {
    equal(add(2, 3), 5, "2 + 3 should equal 5");
});

Or how about a more complicated example. Let’s say you were writing a genetic algorithm engine, and wanted to test your crossover functions. Your functions and their tests might look like:

        $(function () {

            var geneticAlgorithm = {
                onePointCrossOver: function (mom, dad, index) {
                    var result = [];

                    result[result.length] = mom.slice(0, index)
                        .concat(dad.slice(index));

                    result[result.length] = dad.slice(0, index)
                        .concat(mom.slice(index));

                    return result;
                },
                twoPointCrossOver: function (mom, dad, indexA, indexB) {
                    var indexAResult =
                        this.onePointCrossOver(mom, dad, indexA);
                        
                    return this.onePointCrossOver(
                        indexAResult[0], indexAResult[1], indexB);
                }
            };

            function compareResults(actual, expected) {
                equal(actual.length, expected.length, 
                    "The length should be the same.");
                equal(actual.length, 2, 
                    "There should be two children.");

                compareChild(actual[0], expected[0]);
                compareChild(actual[1], expected[1]);
            }

            function compareChild(actual, expected) {
                equal(actual.length, expected.length,
                    "The number of genes should be the same.");

                for (var i = 0; i < expected.length; i++) {
                    equal(actual[i], expected[i], 
                        "The gene at '" + i + "' should be the same.");
                }
            }

            module("Cross Over tests");

            test("onePointCrossOver tests", function () {
                var mom = [1, 2, 3, 4];
                var dad = [5, 6, 7, 8];

                var childA = [1, 2, 7, 8];
                var childB = [5, 6, 3, 4];

                var actual = geneticAlgorithm
                    .onePointCrossOver(mom, dad, 2);
                var expected = [childA, childB];

                compareResults(actual, expected);
            });

            test("twoPointCrossOver tests", function () {
                var mom = [1, 2, 3, 4, 5, 6];
                var dad = [7, 8, 9, 10, 11, 12];

                var childA = [1, 2, 9, 10, 5, 6];
                var childB = [7, 8, 3, 4, 11, 12];

                var actual = geneticAlgorithm
                    .twoPointCrossOver(mom, dad, 2, 4);
                var expected = [childA, childB];

                compareResults(actual, expected);
            });
        });

You can view the results of the tests here. Notice that you can click on each of the tests in the results to get more details. If any of the tests had failed, the failing tests would be marked in red, and expanded, showing the expected value, and the actual value, along with other helpful information.