How to test client-side code with NodeUnit?

This is a follow-up to my previous question.

Suppose I am writing calculate.js source file with calculate function to use it in my client-side code

function calculate(num) {
    return num * 2;
}

Now I would like to test it.

I am using nodeunit as described in this article and export the calculate function (so that tests can invoke it).

function calculate(num) {
    return num * 2;
}

exports.calculate = calculate // node.js stuff. won't run in a browser!

The nodeunit tests run ok but I cannot use calculate.js in my web application any longer since it uses exports.

Now it looks like a catch. Can I fix this problem?

use a non node js testing framework like jasminebdd or jstestdriver

Running tests in the browser

If you wish to use a commonjs format for your test suites (using exports), it is up to you to define the commonjs tools for the browser. There are a number of alternatives and its important it fits with your existing code, which is why nodeunit does not currently provide this out of the box.

I think you should have a look at browserify to accomplish this.

Browserify

Make node-style require() work in the browser with a server-side build step, as if by magic!

Mocha

Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser.

I think you should have a look at Mocha created by TJ(express author) which I like very much(better then nodeunit which I used in the past). With mocha you can easily do code coverage, watch-mode, notifications and as a big plus Mocha is more maintained.

Karma runner has a nodeunit adapter to run nodeunit tests in browsers and Phantom JS. Heres an example test entrypoint and Gruntfile using browserify to run tests written in CommonJS modules (exports).

nodeunit-browser-tap + Testling is another option if you're set on nodeunit.

  • The testling npm package gets you command line output for tests run in a local browser.
  • Testling.com gets you free cross browser CI if you host on Github.
  • The browser-tap wrapper gets you nodeunit output that Testling understands.

You can actually test isolated jquery logic within nodeunit itself. For example, here is some tests I wrote for my datepicker libary

/*jshint evil:true */
/*global module, require, DatePair */

var fs = require('fs');
// Some of the plugins use jQuery var instead of $
var jQuery = require('jquery');
var $ = jQuery;

// Recreate window and document
var window = { jQuery: jQuery };
var document = window;

// file is included here:
eval(fs.readFileSync('../lib/js/jquery/plugins/jquery.cookie.js') + '');
eval(fs.readFileSync('../lib/js/jquery.timepicker/jquery.timepicker.js') + '');
eval(fs.readFileSync('../lib/js/bootstrap/bootstrap-datepicker.js') + '');
eval(fs.readFileSync('../homepage/js/datepair.js') + '');

// Initialize DatePair Object
var datePair = DatePair(new Date(), {
    dateStart: $('<input type="text" autocomplete="off">'),
    dateEnd: $('<input type="text" autocomplete="off">'),
    timeStart: $('<input type="text" autocomplete="off">'),
    timeEnd: $('<input type="text" autocomplete="off">')
});

module.exports = {
    'Time Delta Var Is 1 hour' : function (test) {
        test.equal(datePair.getTimeDelta(), 3600);
        test.done();
    },
    'Change Date And Check For 1 Hour Difference' : function (test) {
        datePair.startTime.val("10:00pm").change();
        test.equal(datePair.endTime.val(), "11:00pm");
        test.done();
    },
    'Make End Date Move Up One Day' : function (test) {
        var expectedEndDates = [1];
        datePair.startTime.val("11:00pm").change();
        expectedEndDates.push(parseInt(datePair.startDate.val().split("/")[1], 10) + 1);

        test.ok($.inArray(parseInt(datePair.endDate.val().split("/")[1], 10), expectedEndDates) !== -1);
        test.equal(datePair.endTime.val(), "12:00am");
        test.done();
    },
    'Change To 11:30pm Of Previous Day' : function (test) {
        //Move startTime 1 Day Forward
        datePair.startTime.val("11:00pm").change();
        //Move EndDate 1 Day Backwards
        datePair.endTime.val("11:30pm").change();

        test.equal(datePair.endDate.val(), datePair.startDate.val());
        test.done();
    }
}

See full code + library here https://github.com/keithhackbarth/jquery-datetime-picker