Venus.js Documentation

Introduction

Getting started

Install Venus.js

  1. Install Node.js:
Please see the instructions at http://www.nodejs.org for getting node.js running on your platform.
  1. Install Venus.js via NPM:
npm install -g venus
  1. Verify installation:
venus demo

Write your first test

Venus.js designed to work with multiple testing libraries (see Supported Libraries).

In the directory of your choice, create a new file (lets call it example.js):

/**
 * @venus-library mocha
 */
describe('First unit test using venus.js', function() {
  it('Gives us the ability to run test from the command line', function() {
    expect(2 + 2).to.be(4);
  });
});

Run your first test

venus run -t example.js -e ghost

Output should look similar to

info:   Serving test: http://172.16.146.107:2013/venus-core/1
info:   Venus server started at http://172.16.146.107:2013 and is serving 1 test suites

 PhantomJS/1.9.1 /home/smclaugh/example.js

   First unit test using venus.js
   --------------------------------------------------------
   ✓ Gives us the ability to run test from the command line


--------------------------------------------------------
  1 tests executed in 899 ms
  1 ✓ tests passed
  0 x tests failed

Run tests in the browser

You can also run tests with Venus manually in a browser. To do this, start Venus without the -e (environment) flag:

venus run -t example.js

info:   Serving test: http://172.16.146.107:2013/venus-core/1
info:   Venus server started at http://172.16.146.107:2013 and is serving 1 test suites

Next, open the first URL printed above in your browser of choice (note: the URL on your machine will be different). You should see a screen similar to this:

_images/venus_ui.png

Getting help

Having issuse getting these examples to work? Check out the Venus.js Google Group.

Tutorials

Debugging failing tests

Sometimes tests will give you a useful message explaining why they failed, but there are other times where they fail or hang without providing a clue of what is going on.

When you are having this issue the best way to debug the issue is to open the test in your favorite browser.

_images/image1.png

There is more happening on the browser than what we see at first glance. If you take a look at the DOM you will see an iframe with a src attribute something like /venus-core/sandbox/1, and this is where all the action happens. In there you can see all the libraries being loaded for your test, the file you are testing and the test code.

_images/image2.png

If you don’t see your script files being loaded, this is a good indicator that something is wrong with your test. This is an example of how the iframe looked on one test were I was triggering a redirect and by doing that breaking my tests:

_images/image3.png

Knowing this is also useful to find out why a test is failing or something is not working as expected. Since you now have access to your JS files from your developer tools you can set break points and go through the code step by step to figure out why something is failing.

_images/image4.png

Test execution environments

Local (Manual)

You can run a unit test with any browser you have installed locally on your machine

Below is an example of running tests.js locally:

$ venus run -t tests.js

PhantomJS

PhantomJS is a headless browser that Venus leverages to seamlessly run unit tests

The command line option -n or –phantom will specify the test to run with PhantomJS

Below is an example of running tests.js with PhantomJS:

$ venus run -t tests.js -n

This is a shortcut to the command:

$ venus run -t tests.js -e ghost

The -e, or --environment flag specifies which test environment to use. For more information, see configuring test environments below.

Selenium Grid

Using a Selenium Grid setup, you can request a VM with a given browser to execute a unit test via Venus. You can configure different environments in your venus config file. Here is a sample config file setup to run tests remotely in several popular browsers, through selenium grid:

environments: {
  ie7: {
    uac: 'WebDriverUac',
    browser: 'internet explorer',
    version: '7.0',
    host: 'selenium-0101.corp.net',
    port: 4444
  },
  ie8: {
    uac: 'WebDriverUac',
    browser: 'internet explorer',
    version: '8.0',
    host: 'selenium-0101.corp.net',
    port: 4444
  },
  ie9: {
    uac: 'WebDriverUac',
    browser: 'internet explorer',
    version: '9.0',
    host: 'selenium-0101.corp.net',
    port: 4444
  }
}

WebDriverUac refers to a Venus User Agent Controller module which understands how to communicate with a selenium grid server. The other options in each section are passed along, to request a specific browser version for running tests.

If I hade a selenium grid server running at selenium-1010.corp.net:4444, I could run this venus command to execute tests on Internet Explorer 8:

$  venus run -t tests.js -e ie8

Sauce Labs

Sauce Labs is a great hosted solution for running your tests on a wide variety of platforms. Venus provides a special UAC for running tests with Sauce Labs. You can set this up in your venus config file by creating an environment like this:

environments: {
  sauce: {
    uac: 'SauceLabsUac',
    host: 'ondemand.saucelabs.com',
    browser: 'firefox',
    version: 20,
    platform: 'OS X 10.6',
    username: 'your_sauce_labs_username',
    accessKey: 'your_sauce_labs_access_key'
  }
}

You would then run your tests through Sauce Labs with this command:

$  venus run -t tests.js -e sauce

Using different testing libraries

Venus simplifies running unit tests for JavaScript. To minimize overhead, we set out to create a tool that makes it easier to work with an existing test library such as Mocha, Jasmine or QUnit.

Mocha

Mocha is a feature-rich test framework that provides a wealth of features, not limited to, but including: async support, watching for slow tests, and integration with various assertion libraries. However, it doesn’t contain integration with any browsers (ex. WebKit). By simply adding Venus annotations, you can use Venus to run your tests using PhantomJS, while still being able to run them using the mocha CLI.

Let’s say you have this test file, tests.js:

describe('Array', function() {
  describe('#indexOf()', function() {
    it('should return -1 when the value is not present', function() {
      expect([1, 2, 3].indexOf(5)).to.be(-1);
      expect([1, 2, 3].indexOf(0)).to.be(-1);
    });
  });
});

In order to make tests.js runnable in Venus, modify your file as follows:

/**
 * @venus-library mocha
 * @venus-template sandbox
 */
describe('Array', function() {
  describe('#indexOf()', function() {
    it('should return -1 when the value is not present', function() {
      expect([1, 2, 3].indexOf(5)).to.be(-1);
      expect([1, 2, 3].indexOf(0)).to.be(-1);
    });
  });
});

NOTE: This file uses expect.js, but can be modified to use any assertion library supported by Mocha.

Now you can run your tests using Venus:

$ venus run -t tests.js -n

info:   Serving test: http://localhost:2013/venus-core/1
info:   executor started on localhost:2013
info:   Phantom browser is loading http://localhost:2013/venus-core/1

--------------------------------------------------------


PhantomJS/1.7.0

   Array >> #indexOf()
     ✓ should return -1 when the value is not present


✓ 1 test completed (0.01ms)

Jasmine

Jasmine is a behavior-driven development framework for testing JavaScript code. By default, it includes an HTML file that serves as a test runner. However, it doesn’t provide a command-line interface to run your unit tests. By simply adding Venus annotations, you can use Venus to run your tests both from the command line, while still preserving the ability to use the HTML test runner.

Let’s say you have this test file, tests.js:

describe('A suite', function() {
  it('contains spec with an expectation', function() {
    expect(true).toBe(true);
  });
});

In order to make tests.js runnable in Venus, modify your file as follows:

/**
 * @venus-library jasmine
 * @venus-template sandbox
 */
describe('A suite', function() {
  it('contains spec with an expectation', function() {
    expect(true).toBe(true);
  });
});

Now you can run your tests using Venus:

$ venus run -t tests.js -n

info:   Serving test: http://localhost:2013/venus-core/1
info:   executor started on localhost:2013
info:   Phantom browser is loading http://localhost:2013/venus-core/1

--------------------------------------------------------


PhantomJS/1.7.0

   A suite
     ✓ contains spec with an expectation


✓ 1 test completed (0ms)

QUnit

QUnit is a JavaScript unit test suite used by jQuery, jQuery UI, and jQuery Mobile. It provides a web page interface for running your unit tests. However, it doesn’t provide a command-line interface to run your unit tests. By simply adding Venus annotations, you can use Venus to run your tests both from the command line, while still preserving the ability to use the web page interface.

Let’s say you have this test file, tests.js:

test( "hello test", function() {
  ok( 1 == "1", "Passed!" );
});

In order to make tests.js runnable in Venus, modify your file as follows:

/**
 * @venus-library qunit
 * @venus-template sandbox
 */

test( "hello test", function() {
  ok( 1 == "1", "Passed!" );
});

Now you can run your tests using Venus:

$ venus run -t tests.js -n

info:   Serving test: http://localhost:2013/venus-core/1
info:   executor started on localhost:2013
info:   Phantom browser is loading http://localhost:2013/venus-core/1

--------------------------------------------------------


PhantomJS/1.7.0

   hello test
     ✓ Passed!


✓ 1 test completed (20ms)

Using fixtures

Why?

@venus-fixture imports HTML markup into your test page and gives you quick access to DOM nodes for testing your client side interactions. Importing HTML fixtures saves you the time otherwise spent stubbing or mocking the DOM or elements.

How?

Include the @venus-fixture directive in your venus annotation block. The argument passed to @venus-fixture is a file path, it’s relative to test file you’re annotating. An example of this directive is below:

@venus-fixture ../fixtures/exampleFixture.fixture.html

The full annotation block to may look like the following:

/**
 * @venus-library mocha
 * @venus-include ../lib/zepto.1.0.min.js
 * @venus-include ../src/Silence.js
 * @venus-fixture ../fixtures/exampleFixture.fixture.html
 */

When you run your test, the markup from exampleFixture.fixture.html will be available on your test page. The ability to test your DOM manipulations and callbacks to user interactions is now at your fingertips.

Examples

Example test directory structure:

// Example Test Folder Structure

|-simpleFixtureExample
  |-lib
    |-zepto.1.0.min.js
  |-specs
    |-exampleFixture.spec.js
  |-fixtures
    |-exampleFixture.fixture.html

The contents of our HTML fixture file exampleFixture.fixture.html:

<div id="example-fixture-container"></div>

Example test uses zepto to verify that our HTML fixture has been loaded on the page:

describe('Testing @venus-fixture', function() {
  it('Loads our html', function() {
    var length = $('#example-fixture-container').length;
    expect(length).to.be(1);
  });
});

Example test verifies that a callback was fired by a click event, and that the arguments passed contained a specific DOM id:

describe('Test event delegation target', function() {
  it('Click target should equal "example-fixture-container"', function() {
    var spy = sinon.spy();

    document.addEventListener('click', spy, true);
    $('#example-fixture-container').trigger('click');

    // Callback gets called once
    expect(spy.calledOnce).to.equal(true);
    // The expected element id was passed
    expect(spy.args[0][0].target.id).to.equal('example-fixture-container');
  });
});

VIM Integration

The venus.vim vim plugin allows you to easily run tests without leaving your editor. Supported commands:

  • :VenusRun – run current file in Venus.js in the PhantomJS environment

We recommend using a nice VIM package manager, such as vundle, to manage your vim plugins. It is also helpful to map the :VenusRun command to a shortcut key, such as F12. You can do this in your .vimrc very easily:

map <F12> :VenusRun<CR>

Reference

Annotations

Venus allows you to use comment-based annotations to define configurations for your unit test:

@venus-library

Indicates the test library you wish to use. The test libraries that are currently supported are mocha, jasmine and qunit (Default value is mocha).

Example using the mocha test library:

/**
 * @venus-library mocha
 */

@venus-include

JavaScript file to include with your unit test. Use a seperate @venus-include annotation for every file you wish to include. The path is relative to the location of your test file.

/**
 * @venus-include dependency1.js
 * @venus-include foo/dependency2.js
 * @venus-include ../bar/dependency3.js
 */

@venus-include-group

Includes the given include group. An include group is a set of JavaScript files to include, defined in the Venus config (.venus/config).

For example, let’s say we want to include a group named groupA, which will include fileA.js and fileB.js

/**
 * @venus-include-group groupA
 */

But before we can actually use that annotation, we need to update our Venus config to define what files are included with groupA

{
  // Include groups
  includes: {
    groupA: [
        'fileA.js',
        'fileB.js'
    ],
    groupB: [
      ...
    ]
  }

}

@venus-fixture

The location of the file that will include HTML on the test harness page. This is useful for including some DOM elements that your JavaScript control depends on. The path is relative to the location of your test file.

Example:

/**
 * @venus-fixture fixtures/Greeter.html
 */

@venus-fixture-reset

Disable the behavior of resetting test HTML fixtures after each test executes (Default value is true)

Example:

/**
 * @venus-fixture-reset false
 */

@venus-template

The location of the file that will serve as your test harness page for your unit test. You typically will not need to use this annotation, unless you are doing something extremely custom (Default value is .venus/templates/default.tl).

Example:

/**
 * @venus-template templates/mytemplate.tl
 */

@venus-code

This annotation is used to include the source code file which is under test. Files included with @venus-code are eligible for code coverage instrumentation, whereas files included with @venus-include are not.

/**
 * @venus-code widget.js
 */

@venus-resource

Make external files available within the sandbox. This makes it possible to do such things as fetching files via AJAX in your unit test.

Here is an example:

/**
 * @venus-library mocha
 * @venus-include jquery.js
 * @venus-resource data1.txt
 * @venus-resource foo/data2.txt
 * @venus-resource foo/bar/data3.txt
 * @venus-resource ../biz/data4.txt
 */

describe('should retrieve data1.txt', function() {
  it('should retrieve data1.txt', function(done) {
    $.get(location.href + '/data1.txt')
    .success(function() {
      expect(true).to.be(true);
      done();
    })
  });

  it('should retrieve data2.txt', function(done) {
    $.get(location.href + '/foo/data2.txt')
    .success(function() {
      expect(true).to.be(true);
      done();
    })
  });

  it('should retrieve data3.txt', function(done) {
    $.get(location.href + '/foo/bar/data3.txt')
    .success(function() {
      expect(true).to.be(true);
      done();
    })
  });

  it('should retrieve data4.txt', function(done) {
    $.get(location.href + '/biz/data4.txt')
    .success(function() {
      expect(true).to.be(true);
      done();
    })
  });
});

@venus-execute

Run code in Node.js before a test runs in the browser.

For example, let’s say you have the following files:
  • Tree.js
  • setup.js
  • setup_async.js
  • Tree.spec.js

Tree.spec.js is a unit test file for Tree.js. However, We need setup.js and setup_async.js to execute before any unit tests are ran in Tree.spec.js

In order to do so, we can define the files as follows:

Tree.js

function Tree(id) {
  this.id = id;
}

setup.js

module.exports.before = function (ctx) {
  console.log('before hook:', ctx);
};

setup_async.js

module.exports.before = function (ctx) {
  var when, def;

  try {
    when = require('when');
  } catch (e) {
    console.log('Run `npm install -g when` before running this example');
    return;
  }

  def  = when.defer();

  setTimeout(function () {
    console.log('before hook: 5 seconds later...');
    console.log('before hook ctx:', ctx);
    def.resolve();
  }, 5000);

  return def.promise;
};

Tree.spec.js

/**
 * @venus-library mocha
 * @venus-code ./Tree.js
 * @venus-execute ./setup.js
 * @venus-execute ./setup_async.js
 */

describe('Tree', function() {
  var tree;

  before(function () {
    tree = new Tree(23);
  });


  it('should have the correct id', function () {
    expect(tree.id).to.be(23);
  });

});

NOTE: Currently, we only support the before hook. We plan to support additional hooks in the future such as after, beforeEach, and afterEach

Command line flags

venus run

Run tests specified as an argument to the -t or –test option. When this command is executed, venus will look for a .venus config file in the current directory or otherwise traverse upwards until one is found. If no config file is found you will recieve an error.

Options:

-h, --help                 output usage information
-t, --test [tests]         Comma separated string of tests to run
-p, --port [port]          port to run on
-l, --locale [locale]      Specify locale to use
-v, --verbose              Run in verbose mode
-d, --debug                Run in debug mode
-c, --coverage             Generate Code Coverage Report
--hostname [host]          Set hostname for test URLs, defaults to your ip address
--no-annotations           Include test files with no Venus annotations (@venus-*)
-e, --environment [env]    Specify environment to run tests in
-r, --reporter [reporter]  Test reporter to use. Default is "DefaultReporter"
-o, --output-file [path]   File to record test results
-n, --phantom              Run with PhantomJS. This is a shortcut to --environment ghost

Basic format:

venus run --test [path to folder containing tests or single test file] [options]

Usage (Run JavaScript tests found in a folder and its subfolders in phantomjs headless browser):

venus run -t myproject/containing/tests --phantom
venus init

Generates a .venus project folder, with a boilerplate config file

Options:

-h, --help             output usage information
-l, --locale [locale]  Specify locale to use
-v, --verbose          Run in verbose mode
-d, --debug            Run in debug mode

Usage:

venus init

Output:

|-.venus/
  |-config
  |-adaptors/
  |-templates/
  |-libraries/

Boilerplate .venus/config file:

// Configuration file for Venus
// All paths can be relative (to the location of this config file) or absolute
{
}

venus demo

Runs an example venus test using Mocha and PhantomJS

Example:

venus demo

Config files

Overview:

Venus searches for a file named ‘config’ in the ‘.venus’ directory then proceeds to walk up the directory tree looking for other ‘.venus/config’ files.

When multiple configs are encountered, the config files will extend one another from the order of the furthest config to the closest (closest config to cwd takes precedence).

What can be specified in .venus/config?

libraries:

The libraries config object gives you a way to create a grouping of files that can be passed as an argument to @venus-library annotation for inclusion on the test harness.

Given the following directory structure:

|-.venus/
  |-config
  |-adaptors/
    |-venus-mocha-1.12.0.js
  |-libraries/
    |-mocha-1.12.0.js
    |-expect.js
    |-sinon.js

Define a library inside the libraries object. The library should include an array called includes that contains an array of filepaths.

// Example snippet from .venus/config

{
  libraries: {
    mocha: {
      includes: [
        'libraries/mocha-1.12.0.js',
        'libraries/expect.js',
        'adaptors/adaptor-template.js',
        'adaptors/venus-mocha-1.12.0.js',
        'libraries/sinon.js'
      ]
    }
  },
  default: {},
  environments: {},
  includes: {},
  binaries: {}
}

Notice that the library will be referenced by the key name (mocha) and anything specified within the “includes” array will be injected into the test harness page (see “@venus-library mocha” below):

// Example file: test/unit/js/someScript.spec.js

/**
 * @venus-library mocha
 * @venus-include ../../js/someScript.js
 */

 describe('My test', function() {
   it('should pass', function() {
     expect(true).to.be(true);
   });
 });
default:

The “default” option allows you to specify one of your libraries as the default library to be included, which frees you from using the @venus-library annotation as in the previous example. It’s useful if you are using the same test libraries across all of your suites/specs, or want to run a default environment.

// Example snippet from .venus/config

{
  default: {
    library: 'mocha',
    environment: 'ghost'
  }
  libraries: {
    mocha: {
      includes: [
        ...
      ]
    }
  },
  environments: {
    ghost: {
      ...
    }
  },
  basePaths: {},
  includes: {},
  binaries: {}
}

In the above example, all of the test using this config would assume that you wanted to include the “mocha” library includes, and “ghost” as your default environment.

/**
 * @venus-include ../../js/someScript.js
 */

 describe('My test', function() {
   it('should pass', function() {
     expect(true).to.be(true);
   });
 });
includes:

Similar to libraries, includes allow us to specify groups of files that can be included on the test harness page, by using the @venus-include annotation.

Specifying an include group can be done like so:

// Example snippet from .venus/config
{
  includes: {
    websockets: [
      '../../bower_components/sio-client/socket.io.js',
      '../../bower_components/jquery/jquery.min.js'
    ]
  },
  default: {},
  libraries: {},
  environments: {},
  basePaths: {},
  binaries: {}
}

Using the created include can be done like so:

/**
 * @venus-include websockets
 */
 describe('My test', function() {
   it('should pass', function() {
     expect(true).to.be(true);
   });
 });
environments:

In this config object, you can define custom environments (e.g. browsers) for use in the CLI. The flag –environment, -e can be used to specify which environment you’d like to use. Below are some commented example environment configurations.

// Example snippet from .venus/config

{
  environments: {

    // Run ie 7.0 on selenium webdriver
    sauce_ie_7: {
      uac: 'WebDriverUac',
      browser: 'internet explorer',
      version: '7.0',
      host: 'selenium.your-server.com',
      port: 4444
    },

    // Run chrome version 42 in sauce labs
    sauce_chrome_42: {
      uac: 'SauceLabsUac',
      host: 'ondemand.saucelabs.com',
      browser: 'chrome',
      version: 42,
      platform: 'OS X 10.9',
      username: 'my_saucelabs_user_name',
      accessKey: '1b0222b9-36ed-414d-865x-e4d14c8a45xf3'
    },

    // Run using a local phantom binary
    ghost: {
      uac: 'GhostDriverUac',
      binaryPath: ['../bin/phantomjs', '../node_modules/phantomjs/bin/phantomjs'],
      host: 'localhost',
      port: '8910'
    }
  },
  default: {},
  libraries: {},
  includes: {},
  basePaths: {},
  binaries: {}
}
basePaths:

The basePaths object defines aliases that can be used within venus annotations for brevity/convenience:

// Example snippet from .venus/config

{
  basePaths: {
    appJs: '../../js'
  },
  default: {},
  libraries: {},
  includes: {},
  environments: {},
  binaries: {}
}

The definition we created above “appJs” will be substituted with ”../../js/” when venus looks for your test file:

// The venus-include path below would resolve to "../../js/" before becoming an absolute path
/**
 * @venus-include appJs/someScript.js
 */

 describe('My test', function() {
   it('should pass', function() {
     expect(true).to.be(true);
   });
 });

Working config example:

See a working config here on github.

Supported Libraries

Venus.js is designed to work with multiple testing libraries. Out of the box, Venus.js supports:

When writing a test, use the @venus-library annotation to indicate which testing library you wish to use (see Annotations).

Here is the same test written with Mocha, Jasmine, and QUnit.

Mocha

Mocha is unique in that you can use your choice of assertion libraries. By default, Venus ships with the expect.js assertion library for use with Mocha.

/**
 * @venus-library mocha
 * @venus-include ../src/Greeter.js
 */

describe('Greeter', function () {

  it('.talk() should format string', function() {
    var greet  = new Greeter(),
        result = greet.talk('Hello %s, how are you doing this fine %s?', 'Seth', 'Thursday');

    expect(result).to.be('Hello Seth, how are you doing this fine Thursday?');
  });

});

Jasmine

/**
 * @venus-library jasmine
 * @venus-include ../src/Greeter.js
 */

describe('Greeter', function () {

  it('.talk() should format string', function() {
    var greet  = new Greeter(),
        result = greet.talk('Hello %s, how are you doing this fine %s?', 'Seth', 'Thursday');

    expect(result).toBe('Hello Seth, how are you doing this fine Thursday?');
  });

});

QUnit

/**
 * @venus-library qunit
 * @venus-include ../src/Greeter.js
 */

test('Greeter', function () {
  var greet  = new Greeter(),
      result = greet.talk('Hello %s, how are you doing this fine %s?', 'Seth', 'Thursday');

  equal(result, 'Hello Seth, how are you doing this fine Thursday?', 'Greeter.talk() formats the string correctly');
});

Development Guide

Build a custom adaptor

Background

Venus uses adaptors to communicate with different test libraries. Each adaptor normalizes the output of it’s respective framework in order for Venus to process the test results.

The libraries currently supported are:

All adaptors can be found in the adaptors folder under the root Venus application.

Inside adaptors, you will find a file named adaptor-template.js. This file serves as the base template for all adaptors.

Example

Let’s say we want to create an adaptor for a test framework named FooBar (library file is named foobar.js)

The first step is to place foobar.js in libraries.

Next, create a file named foobar.js and place it in adaptors.

The contents of foobar.js should do the following:

  1. Instantiate the adaptor function Adaptor() {};
  2. Inherit the adaptor template Adaptor.prototype = new AdaptorTemplate();
  3. Override the following methods, which are defined in adaptor-template.js, based on the FooBar test framework:
    • start()
    • getTestMessage()
    • getTestName()
    • getTestStatus()
    • getTestStackTrace()
    • getTotal()
    • getTotalFailed()
    • getTotalPassed()
    • getTotalRuntime()

Finally, define the configuration for FooBar in ./config:

foobar: {
  includes: [
    'libraries/foobar.js',
    'adaptors/adaptor-template.js',
    'adaptors/foobar-.js'
  ]
}

Now you can add the annotation @venus-library foobar at the top of any JS unit test to use the FooBar test library with your tests.