Home / Blog / 2009 / June /
The code in this post is out of date. The latest code can always be found in the JS Test Driver google code site

In my previous post on QUnit and JS Test Driver I showed how to run your qunit tests with JS Test Driver.

The technique used was to run the tests with qunit, and report either their success or failure to JS Test Driver. This works, but you miss out on the important feedback of exactly which assertions have failed, and why.

This problem has led me to taking a new approach to running qunit tests with JS Test Driver, where I don’t use any of the existing qunit code, and instead just create an interface wrapper that converts qunit style tests and assertions directly into JS Test Driver tests and assertions.

This gives assertion level error reporting, making it much easier to write and debug tests. Essentially this adapter allows you to write native JS Test Driver tests, but using the less verbose qunit syntax.

The new approach also means that qunit lifecycles (setup and teardown) work.

Installing the QUnit Adapter

First up download the equiv.js file, which is required for the qunit same assertion.

Then download the QUnitAdapter.js file (or copy the code below).

QUnitAdapter.js

(function() {
 
    window.module = function(name, lifecycle) {
        QUnitTestCase = TestCase(name);
 
        if (lifecycle) {
            QUnitTestCase.prototype.setUp = lifecycle.setup;
            QUnitTestCase.prototype.tearDown = lifecycle.teardown;
        }
    };
 
    window.test = function(name, test) {
        QUnitTestCase.prototype['test ' + name] = test;
    };
 
    window.expect = function(count) {
        expectAsserts(count);
    };
 
    window.ok = function(actual, msg) {
        assertTrue(msg ? msg : '', actual);
    };
 
    window.equals = function(a, b, msg) {
        assertEquals(msg ? msg : '', b, a);
    };
 
    window.start = window.stop = function() {
        fail('start and stop methods are not available when using JS Test Driver.\n' +
            'Use jsUnit Clock object to deal with timeouts and intervals:\n' + 
            'http://googletesting.blogspot.com/2007/03/javascript-simulating-time-in-jsunit.html.');
    };
 
    window.same = function(a, b, msg) {
        assertTrue(msg ? msg : '', window.equiv(b, a));
    };
 
    window.reset = function() {
    	fail('reset method is not available when using JS Test Driver');
    };
 
    window.isLocal = function() {
    	return false;
    };
 
    window.QUnit = {
    	equiv: window.equiv,
    	ok: window.ok
    };
 
})();

Save both these files to your project (for example tests/qunit/).

Configuring JS Test Driver

To run your qunit tests in JS Test Driver you need to configure it to load the adapter before your qunit tests.

Update your jsTestDriver.conf to load the files:

server: http://localhost:9876
 
load:
  # Add these lines to load the equiv function and adapter in order, before the tests
  # (assuming they are saved to tests/qunit/)
  - tests/qunit/equiv.js
  - tests/qunit/QUnitAdapter.js
 
  # This is where we load the qunit tests
  - tests/js/*.js
 
  # And this loads the source files we are testing
  - src/js/*.js

Running JS Test Driver with qunit tests

Now we can run JS Test Driver and watch as it runs all our qunit tests!

The tests will run as individual JS Test Driver tests, with the format Module Name.Test Name.

Example output:

[PASSED] Module 1.test Test 1
[PASSED] Module 1.test Test 2
[PASSED] Module 2.test Test 1
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (1.00 ms)
  Safari 530.18: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (1.00 ms)

Limitations

There are a few limitations on which qunit tests will successfully be converted.

The tests must run synchronously (which means no use of the qunit stop and start methods).

If you need to test timeouts, intervals, or other asynchronous sections of code, consider using the jsUnit Clock object to deal with timeouts and intervals.

QUnit DOM support is not included. Consider avoiding interacting directly with the browser within your unit tests. But if you do need to, you’ll need to create and remove the DOM objects yourself with each test, or the setup and teardown methods.

QUnit and JS Test Driver

June 21st, 2009

This post has obsoleted been the new QUnit Adapter I created, check it out!

I was very impressed by the new Google JS Test Driver project, which provides a blisteringly fast, and easily automated way of running your Javascript unit tests. See this introduction to JS Test Driver by Miško Hevery for a great overview.

I previously described how to run JS Test Driver automatically with Autotest.

But I have an existing project that uses the jQuery testing framework qunit for testing. I didn’t really fancy rewriting 300+ tests just so I could use the JS Test Driver framework.

So I wrote a converter that automatically converts qunit modules and tests into JS Test Driver TestCases and test methods.

Download Converter and Patched Testrunner

In order to convert from qunit tests I’ve had to add a few extra hooks into the qunit testrunner.js file.

Either download the patched testrunner.js file, or just add the 3 lines below:

234
235
236
237
238
239
240
241
242
243
244
245
    QUnit: {
        // Add the following 3 lines 
        runTest: runTest,
        config: config,
        validTest: validTest,	
 
        // This is existing code	
        equiv: equiv,
        ok: ok,
        done: function(failures, total){},
        log: function(result, message){}
    },

Next download QUnitToTestCases.js and save it to the same folder as testrunner.js. This is the file which converts the qunit tests into TestCases that JS Test Driver understands.

It works by overriding the qunit test() function, and rather than adding the test to qunit, it creates a test method on a TestCase object which, when called by JS Test Driver adds the test to qunit and runs it.

Configuring JS Test Driver

Once you have the patched testrunner.js and QUnitToTestCases.js, you just need to let JS Test Driver know to load them before your qunit tests. They need to be loaded in order, with testrunner.js first, followed by QUnitTiTestCases.js, as the converter modifies some of the testrunner methods.

Update your jsTestDriver.conf to load the files:

server: http://localhost:9876

load:
  # Add these lines to load the testrunner and converter in order, before the tests
  # (assuming the files are saved to tests/qunit/)
  - tests/qunit/testrunner.js
  - tests/qunit/QUnitToTestCases.js
 
  # This is where we load the qunit tests
  - tests/js/*.js
 
  # And this loads the source files we are testing
  - src/js/*.js

Running JS Test Driver with qunit tests

Now we can run JS Test Driver and watch as it runs all our qunit tests!

The tests will run as individual JS Test Driver tests, with the format Module Name.Test Name.

Example output:

[PASSED] Module 1.test Test 1
[PASSED] Module 1.test Test 2
[PASSED] Module 2.test Test 1
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (1.00 ms)
  Safari 530.18: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (1.00 ms)

Limitations

There are a few limitations on which qunit tests will successfully be converted.

The tests must run synchronously (which means no use of the qunit stop and start methods).

Module lifecycles are ignored at the moment, which means setup and teardown functions are not called.

Growl and Autotest work brilliantly together. Autotest runs all your tests in the background every time a file changes, giving you extremely fast feedback on your test driven development. And Growl notifications save you from needing to flip back to the Terminal to see the result of each test run, you get an unobtrusive popup in the corner of your screen showing the success or failure of the tests.

But what about those users working on the Windows platform?

Snarl is a windows counterpart to Growl. Providing much of the same functionality.

And there is a Snarl Ruby gem allowing us to create Snarl notifications from Ruby.

So lets convert our Growl calls to Snarl calls, and get Autotest notifications under Windows.

Installing Autotest, Snarl, and the Growl to Snarl converter

If you haven’t already download and install Ruby.

First up we need to download and install Snarl.

Then we need to install Autotest and the autotest-growl gem (that we are later going to override). Open a command prompt, and type the following (Autotest is part of the ZenTest gem):

gem install ZenTest
gem install ruby-snarl
gem install autotest-growl

Then save the code below to lib/autotest/growl-to-snarl.rb within your project. This code converts any Growl calls to equivalent Snarl calls.

growl-to-snarl.rb

require 'snarl'
module Autotest::Growl
 
  # Display a message through Snarl.
  def self.growl title, message, icon, priority=0, stick=""
    image = File.join(ENV['HOME'], '.autotest-growl', "#{icon}.png")
    image = File.join(GEM_PATH, 'img', "#{icon}.png") unless File.exists?(image)
 
	Snarl.show_message(title, message.inspect, image)
  end
 
end

Next we need to update our .autotest configuration file to include the autotest-growl gem, and the Growl to Snarl converter. Add the following to your .autotest file in the project root directory.

require 'autotest-growl'
require 'snarl'
require 'lib/autotest/growl-to-snarl'

Running Autotest with Snarl support

First up ensure Snarl is running (check for the icon in the system tray).

Autotest will fail to run on Windows if a HOME environment variable doesn’t exist, so we need to create one before we run (I’ve also noticed that the Ruby gem command will fail to run if the HOME evironment variable does exist, which is frustrating!).

Open a command prompt, navigate to the project root directory. Then enter the following to set the HOME environment variable and run Autotest.

set HOME="C:\Documents and Settings\username"
autotest

The results of your test runs should now display as Snarl notifications.

Autotest and JS Test Driver

June 19th, 2009

Google recently released a new Javascript testing framework, JS Test Driver. It provides incredibly fast execution for Javascript unit tests, and can be run from the command line without the need for manual control of browsers. Check out this introduction to JS Test Driver by Miško Hevery.

Fast test execution and the ability to be run from the command line make it a perfect fit to integrate into the Autotest test cycle. So I have.

The module below hooks into Autotest just before the normal tests are run. It runs JS Test Driver over all the tests in the project, outputs the results, and finally fires off a :ran_js_test_driver hook.

Errors and failed tests will automatically be notified through Growl (if Growl and autotest-growl are installed). By default successful tests runs are not notified through Growl, in order to keep distracting popups to a minimum.

Installing Autotest JS Test Driver

First you need to download a copy of JS Test Driver.

Save the JS Test Driver jar file to the lib/ directory within your project.

Then copy the code below to lib/autotest/js-test-driver.rb

js-test-driver.rb

# Run JS Test Driver as part of autotest
# Supports Growl notifications if using autotest-growl
 
require 'autotest'
 
module Autotest::JsTestDriver
 
    @@jar = File.dirname(__FILE__) + '/JsTestDriver-1.0b.jar'
    @@config_file = 'jsTestDriver.conf'
 
    def self.jar=(string)
        @@jar = string
    end
 
    def self.config_file=(string)
        @@config_file = string
    end
 
    def self.show_success=(bool)
        @@show_success=bool
    end
 
 
    Autotest.add_hook :run_command do |at|
        # run js test driver
        results = 'JS Test Driver:'
        results += `java -jar "#{@@jar}" --config "#{@@config_file}" --tests all --verbose`
        puts results
 
        at.results = [] if at.results.nil?
        at.results.concat(results.split("\n"))
 
        at.hook :ran_js_test_driver
 
    end
 
end
 
module Autotest::Growl
 
    @@show_js_test_success = false
 
    def self.show_js_test_success=(bool)
        @@show_js_test_success=bool
    end
 
  # Growl results of JS Test Driver
  Autotest.add_hook :ran_js_test_driver do |autotest|
 
    gist = autotest.results.grep( /Total\s+\d+\s+tests/ ).join(" / ").strip()
 
    if gist == ''
      growl @label + 'Cannot run JS Test Driver.', gist, 'error'
    else
      if gist =~ /Errors:\s+[1-9]\d*/
        growl @label + 'Error running some JS tests.', gist, 'failed'
      elsif gist =~ /Fails:\s+[1-9]\d*/
        growl @label + 'JS Test: Some tests failed.', gist, 'failed'
      elsif @@show_js_test_success
        growl @label + 'JS Test: All files are clean.', gist, 'passed'
      end
    end
    false
  end
 
end

Configuring Autotest and JS Test Driver

JS Test Driver uses a configuration file to connect with the JS Test Driver server, and to decide which javscript files to load.

Create a jsTestDriver.conf file in the project root directory as follows.

server: http://localhost:9876

load:
  - src/js/*.js
  - tests/js/*.js

This assumes that you have our javascript source files will be in the src/js/ directory, and our javascript test files will be in the src/js/ directory. We will create a test file, and associated code later.

The server: lets JS Test Driver know we will be connecting to a server on our local machine, on port 9876. We’ll get this server running later.

Next we need to configure Autotest to run JS Test Driver, by requiring the module and specifying the location of the JS Test Driver jar.

# Require the JS Test Driver module
require 'lib/autotest/js-test-driver'
 
# Set the location of the JS Test Driver jar
Autotest::JsTestDriver::jar = './lib/jsTestDriver-1.0b.jar'

You can also configure the location of the JS Test Driver config file, and whether or not to show successful test runs.

# Uncomment this if you have autotest-growl, and Growl installed
# And want to have notifications of JS Test Driver runs
# require 'autotest/growl'
 
# Uncomment this to change the location of the JS Test Driver config file
# By default we look for a jsTestDriver.conf file in the directory autotest is run from 
# Autotest::JsTestDriver::config_file = './jsTestDriver.conf'
 
# Uncomment this to show successful test runs
# Autotest::Growl::show_js_test_success = true

Now that all the installation and configuration is done, let get everything running.

Running Autotest with JS Test Driver

First up we need to get our JS Test Driver server up and running. Open a Terminal, and navigate to the directory containing the JS Test Driver jar. Run the following to start a server:

java -jar JsTestDriver-1.0b.jar --port 9876

Now we need to capture a browser to use for testing. Open a browser and automatically capture it for use with JS Test Driver by going to the following URL:


http://localhost:9876/capture

Now we can run autotest, and watch as it runs JS Test Driver and reports the results to us on every file change:

autotest

JS Test Driver will probably report that no tests were run, as we haven’t written any tests yet. Tests are written using the TestCase object, which exposes JUnit style functionality.

Writing Some Tests

Here is an example test file, and the production code it tests:

GreeterTest.js

GreeterTest = TestCase("GreeterTest");
 
GreeterTest.prototype.testGreet = function() {
  var greeter = new myapp.Greeter();
  assertEquals("Hello World.", greeter.greet("World"));
};

Greeter.js

myapp = {};
 
myapp.Greeter = function() { };
 
myapp.Greeter.prototype.greet = function(name) {
  return "Hello " + name + "!";
};

If you copy these to your tests/js/ and src/js/ directories respectively, Autotest should pick up the new files, run the tests and notify you that there is an error. See if you can spot it :P

To Do

This would be nice packaged up as a gem. It would also be nice if failed Javascript tests could stop further tests being run.

As an example of getting Autotest, Cucumber, and Growl up and running I’ve created a super simple test project. You can download the example project, or just create it from the code on this post.

Install Ruby, Growl, and Gems

First up we need to ensure that we have all our dependancies installed.

If you haven’t already, download and install Ruby.

Then we need to install the Autotest, Cucumber, and Growl Ruby gems. We can do this using the gem command that comes packaged with Ruby.

# Autotest test is part of the ZenTest gem
sudo gem install ZenTest
sudo gem install cucumber
# Use my modified autotest-growl gem (until the changes are merged into the official gem)
sudo gem install karl-autotest-growl --source http://gems.github.com

Next we need to ensure that the Growl application itself is installed. If not download and install Growl.

Create Project

Now we are ready to create our project. The either download the example project or create the file heirarchy below:

  • [dir] Autotest-Cucumber

    • [file] .autotest
    • [dir] features
      • [file] test.feature

Copy the code below into the .autotest file:

.autotest

require 'autotest/growl'

And the copy the following into the test.feature file:

test.feature

Feature:
 
    Scenario:
        Given I save 1
        Then I have 1

Set Environment

Lastly we need to set the AUTOFEATURE environment variable to true, so that autotest will run the Cucumber tests automatically:

AUTOFEATURE=true

Run Autotest!

Finally we can run autotest, and watch as it picks up the Cucumber tests, runs them, and notifies us via Growl. Open terminal and navigate to the project directory. Then run autotest:

autotest

Autotest will initiate a Cucumber run. Cucumber will pick up the test.feature file (because it looks for a features folder by default). The Cucumber run will show that you have 1 undefined scenario (and be kind enough to give you the code for your undefined steps). And finally Growl will display a notification that you have 1 undefined scenario, yay!

c:/ruby/bin/ruby c:/ruby/lib/ruby/gems/1.8/gems/aslakhellesoy-cucumber-0.3.11.3/bin/cucumber --format progress --format rerun --out C:/Temp/autotest-cucumber.17824.1 features
UU
 
1 scenario (1 undefined)
2 steps (2 undefined)
0m0.000s
 
You can implement step definitions for undefined steps with these snippets:
 
Given /^I save 1$/ do
  pending
end
 
Then /^I have 1$/ do
  pending
end

Following on to my previous post on Autotest, Cucumber, and Growl, I have forked the autotest-growl repository, and applied my fix for Cucumber notifications.

You find my patched version of autotest-growl on GitHub.

You can switch to this version of autotest-growl by uninstalling any existing version, and then installing from my fork on GitHub:

sudo gem uninstall autotest-growl
sudo gem install karl-autotest-growl --source http://gems.github.com

As well as using Autotest to run Cucumber scenarios I have also been looking into integrating lower level test into the Autotest cycle.

My first attempt at this is a small module to run Javascript Lint on all the javascript files within a project any time any file changes.

The module below hooks in to Autotest just before the tests are normally run. It runs javascript lint over all the *.js files in the project, outputs the results to the autotest results object and the standard output, and finally fires a new ran_javascript_lint hook

Errors and warnings found by Javascript Lint will also be notified through Growl (if Growl and autotest-growl are installed). If there are no errors or warnings than no Growl notification is shown. This keeps distracting popups to a minimum.

Installing Autotest Javascript Lint

First up, download Javascript Lint. Extract the jsl executable to lib/autotest/ within your project.

Copy the code below to lib/autotest/javascript-lint.rb within your project (the same directory where you have the jsl execuatable).

javascript-lint.rb

# Run Javascript Lint as part of autotest
# Supports Growl notifications if using autotest-growl
#
# Version 1.0
 
require 'autotest'
 
module Autotest::JavascriptLint
    @@js_dir = ''
    @@jsl_dir = File.dirname(__FILE__) + '/'
    @@config_file = ''
 
    def self.js_dir=(string)
        @@js_dir = string
    end
 
    def self.jsl_dir=(string)
        @@jsl_dir = string
    end
 
    def self.config_file=(string)
        @@config_file = string
    end
 
    Autotest.add_hook :run_command do |at|
 
        # run javascript lint
        results = `#{@@jsl_dir}jsl -conf "#{@@config_file}"  -process "#{@@js_dir}*.js" +recurse`
        puts results
 
        at.results = [] if at.results.nil?
        at.results.concat(results.split("\n"))
 
        at.hook :ran_javascript_lint
    end
 
end
 
module Autotest::Growl
 
    @@show_js_lint_success = false
 
    def self.show_js_lint_success=(bool)
        @@show_js_lint_success=bool
    end
 
    # Growl results of Javscript Lint
    Autotest.add_hook :ran_javascript_lint do |autotest|
        gist = autotest.results.grep(/\d+\s+error.*,\s+\d+\s+warning.*/).join(" / ").strip()
 
        if gist == ''
            growl @label + 'Cannot run javascript lint.', '', 'error'
        else
            if gist =~ /[1-9]\d*\s+(error)/
                growl @label + 'Lint: Some files have errors.', gist, 'failed'
            elsif gist =~ /[1-9]\d*\s+(warning)/
                growl @label + 'Lint: Some files have warnings.', gist, 'pending'
            elsif @@show_js_lint_success
                growl @label + 'Lint: All files are clean.', gist, 'passed'
            end
        end
        false
    end
 
end

Then add Autotest Javascript Lint to your .autotest configuration file within the base of your project.

require 'lib/autotest/javascript-lint'

To Do

This could be packaged as a gem for easy installation, and it could possibly be modified to only run over changed files.

Autotest is a great Ruby tool to speed up test driven development by automatically running your tests every time a file is saved.

Cucumber is an awesome tool for doing behavioural driven development. It allows you to write plain text automated acceptance tests.

Autotest and Cucumber work together seamlessly, you just need to set the AUTOFEATURE environment variable to true:

$ AUTOFEATURE=true

Growl is an excellent notification system for OSX that allows applications to popup unobtrusive messages on the users desktop. (Snarl is the equivalent for windows)

You can add Growl support to Autotest (using the autotest-growl gem) so that you get popup notifications of test results.

But the current version of autotest-growl doesn’t provide notifications for the result of Autotest Cucumber runs.

Cucumber Growl support in Autotest

So I’ve added support for notification of Autotest Cucumber results using growl. It’s super simple at the moment as I’m still pretty new at Ruby.

You need to have Autotest (part of the ZenTest gem), Autotest-Growl, and Growl already installed.

Save the code below to the file growl-cucumber.rb.

growl-cucumber.rb

require 'autotest'
 
module Autotest::Growl
 
  # Growl results of Cucumber
  Autotest.add_hook :ran_features do |autotest|
 
	gist = autotest.results.grep(/\d+\s+scenario.*\)/).join(" / ").strip()
	if gist == ''
	  growl @label + 'Cannot run features.', '', 'error'
	else
	  if gist =~ /[1-9]\d*\s+(failed)/
	    growl @label + 'Some features have failed.', gist, 'failed'
	  elsif gist =~ /pending/
	    growl @label + 'Some features are skipped.', gist, 'skipped'
	  else
	    growl @label + 'All features have passed.', gist, 'passed'
	  end
	end
    false
  end
 
end

Then update your .autotest configuration file to include the new growl-cucumber file:

.autotest

# Add the growl and growl-cucumber requires to your .autotest config file 
require 'autotest/growl'
require 'autotest/growl-cucumber'

To Do

I need to see if this can be integrated with the existing autotest-growl gem.