March 28, 2013

Drive Mocha-PhantomJS with CoffeeScript

PhantomJS opened up to me in a major way once I discovered I was able to drive it with Mocha. I still, however, find creating HTML pages for tests very cumbersome, and far from DRY. And I want to write my tests in CoffeeScript, dammit!

░░░░░░░░░░░░▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄░░░░░░░░░░░░░
░░░░░▄▄▄▄█▀▀▀░░░░░░░░░░░░▀▀██░░░░░░░░░░░
░░▄███▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█▄▄▄░░░░░░░
▄▀▀░█░░░░▀█▄▀▄▀██████░▀█▄▀▄▀████▀░░░░░░░
█░░░█░░░░░░▀█▄█▄███▀░░░░▀▀▀▀▀▀▀░▀▀▄░░░░░
█░░░█░▄▄▄░░░░░░░░░░░░░░░░░░░░░▀▀░░░█░░░░
█░░░▀█░░█░░░░▄░░░░▄░░░░░▀███▀░░░░░░░█░░░
█░░░░█░░▀▄░░░░░░▄░░░░░░░░░█░░░░░░░░█▀▄░░
░▀▄▄▀░░░░░▀▀▄▄▄░░░░░░░▄▄▄▀░▀▄▄▄▄▄▀▀░░█░░
░█▄░░░░░░░░░░░░▀▀▀▀▀▀▀░░░░░░░░░░░░░░█░░░
░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▄██░░░░
░░▀█▄░░░░░░░░░░░░░░░░░░░░░░░▀▀▀░░░░░▀█░░
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
█▀▄░█▀▀░█▀█░█░░░░█░▄░█░█░▀█▀░█░█░░█░▀█▀░
█░█░█▀▀░█▀█░█░░░░▀▄▀▄▀░█░░█░░█▀█░░█░░█░░
▀▀░░▀▀▀░▀░▀░▀▀▀░░░▀░▀░░▀░░▀░░▀░▀░░▀░░▀░░
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

You can accomplish this fairly easily with a framework like Brunch that concatenates and compiles CoffeeScript by design. But I was knee deep (neck deep?) in a project with a completely custom build process that I needed to work in harmony with.

Drop-in ready

I have a pretty lightweight solution using an Eco-templated PhantomJS HTML harness generated dynamically from one or more CoffeeScript test runners. This allows me to just add new CoffeeScript tests at will.

If you want to skip directly to the code here is the gist

The system basically runs all of your tests from a make target that uses mocha-phantomjs:

test: build
    for HTML_FILE in $(shell ls ${BUILD_DIR}html) ; do \
        ${NODE_MODULES_DIR}.bin/mocha-phantomjs \
            ${BUILD_DIR}html/$$HTML_FILE ; \
    \
    done

Where the BUILD_DIR contents is in turn generated by some CoffeeScript in build.coffee.

Configuration

Configuration happens in the template file phantom.eco.

Protip: One of the most useful things about mocha configuration is globals, e.g.:

mocha.globals([
    '$',        // jquery
    'jQuery',   // jquery
    'jQuery*'   // jquery JSONP
]);

You get a great warning of global variable leaks in your scripts under test and can suppress any specific ones here.

Run a complete example

As long as you have node.js, NPM, and make installed:

  1. Download the gist
  2. (from the unzipped directory)

    npm install
    

    followed by

    make
    

This should actually run a headless test and give you a successful output to the console. You can also open the generated HTML in any browser and run the same test.

open ./build/html/addtwonumbersasync_spec.html

It's probably best to move the different types of files into different directories but everything is currently flattened so it works as a gist.