Browser Harness ===============

Browser Harness

  • Simple - Use jQuery to interact with items on the page and check expected conditions. Optional fibers support makes test writing and reading straightforward.
  • Fast - Can perform 50+ actions per second in the browser
  • Cross-browser - Tests run on any modern web browser, and even some old ones
  • Flexible - Write tests in whatever node.js framework you want
              Tested    "Should work"
Chrome 4+        ✓
Firefox 3+       ✓
Safari 3+        ✓
Opera 10.61+                  ✓
IE 5.5+                       ✓
IE 8+            ✓
iOS              ✓
Android                       ✓
PhantomJS        ✓
SlimerJS                      ✓
Other                         ✓
  • Your tests include the browser-harness module and tell it to start listening for connections
  • Your test (or some outside process) opens a browser to http://your-test-site/path/to/harness.html?host=path-to-the-browser-harness-server
  • Harness.html connects to the browser harness server, and begins running your tests
  • Your tests will control a browser running within an iframe in harness.html

A standalone example of using browser harness can be found under the browser-harness-bootstrap-tests repository.

The following example uses mocha, but any test framework may be used.

//This little utility function helps reduce the boilerplate needed by each test 
var _it = function(nameexec){
  it(name, function(done){
    asyncblock(exec, done);
describe('An abridged test of the bootstrap docs', function(){
  var driver, testBrowser;
    //Tell the browser harness to listen for connections on port 4500 
    harness.listen(4500, function(){
      //This event is fired when a browser makes a connection and is ready'ready', function(_driver){
        driver = _driver;
      //The harness.Browser class can be used to spawn browser instances 
      //Here, we're using default settings for Chrome 
      testBrowser = new harness.Browser({ type: 'chrome' });
      //Tell the browser to open the harness page 
      //By default, the test will connect to the harness server at localhost:4500 
      //Pass host=address on the query string to change the address'http://localhost:8000/harness.html');
  it('Loads index.html', function(done){
    //setUrl tells the browser to navigate to the page. 
    //The callback is called once the load event of the page has been called 
    driver.setUrl('http://localhost:8000/index.html', done);
  //This test uses the _it method defined above, 
  //which lets code be written in "blocking style" 
  _it('Finds the h1 element', function(done){
    //findVisible finds an element only if it exists and is visible 
    //It accepts any jQuery selector 
    var h1 = driver.findVisible('.masthead h1');
    //findVisible returns an object that behaves like a jQuery variable 
    assert.equal(h1.length, 1);
    //The call to .html() makes a roundtrip to the browser, but fibers makes it 
    //so we don't have to deal with callbacks directly 
    assert.equal(h1.html(), 'Bootstrap');
  _it('Clicks on javascript', function(){
    //The selector used here is not ideal. Usually we want to select by an id or class 
    //For testing your own applications, it's generally better to 
    //modify the code than use goofy selectors 
    driver.findVisible('a[href="./javascript.html"]').click(); //jQuery chaining works 
    //Browser harness encourages you not to wait for explicit time periods. 
    //In fact, it doesn't even have a built-in sleep function 
    //Instead, use conditions that indicate when it's safe to continue test execution 
      //This function runs from within the browser context 
      return location.href.indexOf('/javascript.html') >= 0;
  _it('Clicks on Modal', function(){
        return location.href.indexOf('#modals') >= 0;
  _it('Launches the demo modal', function(){
    var modal = driver.findVisible('#myModal');
    //You can call findVisible(s)/findElement(s) on elements 
    //to scope the call to children of that element 
    modal.findVisible('.modal-footer .btn[data-dismiss=modal]').click();
    //The close is animated, so need to wait for it 
      return $('#myModal').css('display') === 'none';
    //Close the browser instance that we spawned 

The module has built-in support for fibers via asyncblock]( To take advantage of it, all you need to do is install asyncblock from npm and wrap your test with it (see above for an example).

Browser harness will auto-detect that asyncblock is being used and turn all asynchronous calls into "blocking-style".

Note that using fibers to write the tests is optional, but it is highly recommended. See no-fibers.js for an example of writing tests without fibers.

Due to the way browser harness interacts with the browser, there are a few limitations.

  • Requires harness.html be served from the domain of the site/application being tested
    • Warning: Be careful not to include harness.html in production, as it opens a potential cross-site scripting attack vector
  • Can only interact with pages hosted from within a single domain (barring some CORS configuration)
  • Can not upload files from the local computer (but should be able to spoof file uploads via javascript)
  • Can not interact directly with cookies that have the httponly flag


There are tests for browser harness located under the "tests" folder.

To run the tests:

cd tests
#Install test dependencies
npm install
#Run test with mocha. Set a 10 second timeout as sometimes it takes a bit for the browser to open initially
#You can also use your global mocha installation if you have it installed already
./node_modules/mocha/bin/mocha all_tests.js -R spec -t 10000
#Edit the test_browser file to run the tests in a different browser (defaults to phantomjs)
  • More streamlined browser integration (windows)
  • Handle alert, input, etc.
  • Cookie handling
  • SlimerJS integration
  • Ability to take screen shots with phantomjs / slimerjs (possible with others?)
  • Switch out NowJS support for plain Socket.IO for easier Windows support
  • Better support detecting javascript errors in the browser
  • Build in support for other event types like right click, mouse down, mouse up, keys, etc.
  • More robust error handling
  • See what can be done to make it easier to interact with file upload controls
  • "Ease of use" improvements around common functions, like waiting for a specific page
  • Documentation