Continuously integrated JS development

with Buster.js and Phantom.js

More updated slides based on these can be found here

Tiago Rodrigues

@trodrigues

trodrigues.net

Lead JS dev @ Top10.com

Part of the LxJS organizing committee

Loads of dev across different browsers, different libraries

Testing

You are testing your code...right?

We know, tests are a pain in the ass
How many people here don't write tests?

Testing

If you don't run your tests, they are worthless

Run early, run often
On file change, on push, CI

Testing

Sooner or later, you will forget to run your tests

if you do it manually

Testing

Testing webapps is not so straightforward

DOM fixtures, browser environments, etc

Testing

Our testing tools need to make it easy for us

So far it's been a pain in the ass

Testing @ Top10

  • Buster.js
  • Phantom.js
  • Jenkins (building, deployment, CI)
  • Selenium (not quite there yet)

Buster.js

  • Full fledged JS testing framework
  • Works very well in node.js and browsers
  • Still in beta, very stable since beta 2
  • A few quirks, docs are improving
  • Doesn't work well in Windows

Windows main priority at the moment

Why Buster.js?

It's like Mocha, Jasmine and JSTestDriver had a genetically engineered baby

Mostly all the features of all of those frameworks, but well put together

And it has a test runner!

Mocha and Jasmine features, + a test runner
test runners, how do they work?

Buster.js

  • Open various browsers
  • Run tests
  • ?????
  • Profit!

no need to go and refresh

Buster.js

Support for AMD


npm install buster-amd
            

Buster.js

Support for AMD


var config = module.exports;
config["web-module"] = {
    environment: "browser",
    rootPath: "js",
    sources: ["someModule.js"],
    tests: ["test/*-test.js"],
    libs: ["require.js"],
    extensions: [require("buster-amd")]
};
            

Buster.js

Support for AMD


// someModule.js
define([], function() {
    return { name: "module" };
});
            

Buster.js

Support for AMD


// someModule-test.js
define(["someModule"], function(mod) {
    buster.testCase("some test", {
      "test that fails" : function() {
          assert.match(mod, {name: "wrong name"});
      },
      "test that succeeds" : function() {
          assert.match(mod, {name: "module"});
      }
    });
});
            

Why not something else?

Mocha, Jasmine, JSTD, Qunit?

Qunit

  • Browser only
  • Bit old and limited
  • No test runner

JSTestDriver

  • Heavy
  • Some crazy bugs

Mocha

  • No test runner by default
  • Refresh to run tests
  • Include external files to test page

Jasmine

  • Refresh to run (by default)
  • Written in Ruby, Node.js version is separate
  • Vibrant community
  • 3rd party test runners, headless runners

Testing can be a pain

Buster.js has all in one package

Not usually a fan of all in one, but it's handy in this case

Phantom.js

  • Headless Webkit
  • It's just webkit, but it's better than nothing
  • Setting up a browser lab can be cumbersome

Phantom.js

  • Available for Linux, OSX, Windows
  • Easy to install
  • No need for xvfb in latest version

Running Buster.js tests with Phantom.js


$ npm install buster
$ ls node_modules/buster
            

You can install the test suite globally

Running Buster.js tests with Phantom.js


$ cat ./scripts/server.sh
#!/bin/bash
# run this before https://gist.github.com/2630210
./node_modules/buster/bin/buster-server & # fork to a subshell
sleep 4 # takes a while for buster server to start
phantomjs ./node_modules/buster/script/phantom.js &
            

Running Buster.js tests with Phantom.js


var page = new WebPage();
page.open("http://localhost:1111/capture", function(status) {
  // setup some redirectors for console.logs and alerts
});
            

Running Buster.js tests with Phantom.js


scripts: {
  "server": "./scripts/server.sh",
  "test": "./node_modules/buster/bin/buster-test --reporter dots"
}
            

Running Buster.js tests with Phantom.js


$ npm run-script server
$ npm test
            

Running Buster.js tests with Phantom.js

Sometime in the future...

  • Run buster-test
  • If no browsers are captured
  • If Phantom.js is present
  • Starts server in background, runs tests

On your CI box...

  • Install Phantom.js
  • Install Buster.js (if not checked in)

On Jenkins

If Buster.js is checked in, run npm rebuild


npm run-script server
./node_modules/buster/bin/buster-test --reporter xml > test/test-report.xml &
            

On Jenkins

Phantom.js and Travis CI

  • CI for open source projects
  • Private projects some day?
  • Test framework agnostic

Phantom.js and Travis CI

  • Checked in dependencies?
  • Just run npm test
  • If buster.js is in your dependencies it will be installed

Phantom.js and Travis CI

  • Don't want to add buster.js to your dependencies
  • Setup a before_install script

Phantom.js and Travis CI

Setup Phantom.js (with xvfb)

http://about.travis-ci.org/docs/user/gui-and-headless-browsers/

Testling

  • Easily run tests in the cloud
  • Real browsers
  • Non test framework agnostic

Browserstack

  • Test framework agnostic
  • Real browsers
  • Some setup required

That's all folks!