Please see the instructions at http://www.nodejs.org for getting node.js running on your platform.
npm install -g venus
venus demo
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);
});
});
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
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:
Having issuse getting these examples to work? Check out the Venus.js Google Group.
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.
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.
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:
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.
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 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.
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 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
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 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 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 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)
@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.
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.
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');
});
});
The venus.vim vim plugin allows you to easily run tests without leaving your editor. Supported commands:
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>
Venus allows you to use comment-based annotations to define configurations for your unit test:
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
*/
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
*/
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: [
...
]
}
}
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
*/
Disable the behavior of resetting test HTML fixtures after each test executes (Default value is true)
Example:
/**
* @venus-fixture-reset false
*/
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
*/
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
*/
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();
})
});
});
Run code in Node.js before a test runs in the browser.
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
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
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 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).
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);
});
});
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);
});
});
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);
});
});
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: {}
}
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);
});
});
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 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?');
});
});
/**
* @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?');
});
});
/**
* @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');
});
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.
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:
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.