This guide covers the ins-and-outs of tape, a simple TAP-producing test library for node and browsers. The tape API is a small superset of the node core assert module.
This guide was written for Testling. Testling lets you write continuous integration cross-browser tests that run on every git push! Once the tests run you get a badge you can put in your readme with the current browser test status. Here's how it looks:
For an exaustive list of all the methods that tape supports, consult the tape readme.
Simple equality with a plan
Most of the time, you'll just need to plan out a few simple asserts with t.equal()
, which uses ===
internally:
var test = require('tape');
test('basic arithmetic', function (t) {
t.plan(2);
t.equal(2 + 3, 5);
t.equal(7 * 8 + 9, 65);
});
If you want you can leave off the test name and just do:
var test = require('tape');
test(function (t) {
t.plan(2);
t.equal(2 + 3, 5);
t.equal(7 * 8 + 9, 65);
});
Simple equality with an end
If you have an indefinite number of assertions, sometimes it's easier to call t.end()
instead:
var test = require('tape');
test('basic arithmetic', function (t) {
t.equal(2 + 3, 5);
t.equal(7 * 8 + 9, 65);
t.end();
});
Deep equality
To compare array and object references deeply, you can use t.deepEqual()
:
var test = require('tape');
test('deep equality', function (t) {
t.plan(2);
t.deepEqual([ 3, 4, 5 ], [ 3, 4, 2+3 ]);
t.deepEqual(
{ a: 7, b: [ 8, 9 ] },
{ a : 3+4, b: [ 4*2 ].concat(3*3) }
);
});
Comparing booleans
Just use .ok()
to assert truthiness:
var test = require('tape');
test('comparing booleans', function (t) {
t.plan(1);
t.ok(3 > 4 || 5 > 2);
});
Negations
For each kind of assertion, prepend (and camel-case) a "not" to turn it into a negative assertion:
var test = require('tape');
test('negatives', function (t) {
t.plan(3);
t.notEqual(1+2, 5);
t.notDeepEqual([1,2], [12]);
t.notOk(false);
});
Pass/fail
If you need a test to just fail, you can call t.fail()
:
var test = require('tape');
test('empty map', function (t) {
[].map(function (x) {
t.fail('this callback should never fire');
});
t.end();
});
Conversely, there is a t.pass()
which always succeeds:
var test = require('tape');
test('map with elements', function (t) {
t.plan(2);
[2,3].map(function (x) {
t.pass();
});
});
More info
You can always add an assertion description as the last argument:
var test = require('tape');
test('more info', function (t) {
t.plan(2);
t.equal(1+2, 3, 'basic arithmetic still works');
t.ok(3+4>5, 'inequalities are as we might expect');
});
Asynchronous
Since we either plan out the number of assertions explicitly with t.plan(n)
or end the test explicitly with t.end()
, we don't need to do anything differently when our tests make asynchronous calls:
var test = require('tape');
test('asynchronous results', function (t) {
t.plan(2);
t.equal(2+3, 5);
setTimeout(function () {
t.equal(5+5, 10);
}, 500);
});
Multiple serial tests
var test = require('tape');
test('first', function (t) {
t.plan(1);
setTimeout(function () { t.ok(true) }, 200);
});
test('second', function (t) {
t.plan(1);
setTimeout(function () { t.ok(true) }, 100);
});
The 'first'
test will run, then the 'second'
.
Nesting tests
You probably shouldn't do this very often, but you can have nested tests too:
var test = require('tape');
test('nested', function (t) {
t.test(function (st) {
st.plan(1);
st.equal(1+2, 3);
});
t.test(function (st) {
st.plan(1);
setTimeout(function () {
st.pass();
}, 100);
});
});
Running a tape test in node
Just run your test file directly with node
:
$ node test/def.js TAP version 13 # defined-or ok 1 empty arguments ok 2 1 undefined ok 3 2 undefined ok 4 4 undefineds ok 5 false[0] ok 6 false[1] ok 7 zero[0] ok 8 zero[1] ok 9 first arg ok 10 second arg ok 11 third arg 1..11 # tests 11 # pass 11 # ok
Running a directory full of tape tests in node
If you npm install -g tape
, you get a test runner for running directories full of tests all at once:
$ tape test/*.js TAP version 13 # defined-or ok 1 empty arguments ok 2 1 undefined ok 3 2 undefined ok 4 4 undefineds ok 5 false[0] ok 6 false[1] ok 7 zero[0] ok 8 zero[1] ok 9 first arg ok 10 second arg ok 11 third arg # (anonymous) ok 12 should be equal 1..12 # tests 12 # pass 12 # ok
You could also use the test runner from the tap module for more terse output. First npm install -g tap
, then do:
$ tap test/*.js ok test/def.js ........................................ 12/12 ok test/falsy.js ........................................ 2/2 total ................................................. 14/14 ok
In the test runner scripts for both tap and tape you will get lots of output including line numbers when an assertion fails.
Running a tape test in a browser
First npm install -g browserify
, then you can do:
$ browserify test.js > bundle.js $ echo '<script src="bundle.js"></script>' > test.html
Then open test.html
in a browser and look at the test output in the debugger. tape writes all its output to console.log()
by default.
If you want to run your tests in a real headless browser locally, npm install -g testling
then do:
$ browserify test.js | testling TAP version 13 # defined-or ok 1 empty arguments ok 2 1 undefined ok 3 2 undefined ok 4 4 undefineds ok 5 false[0] ok 6 false[1] ok 7 zero[0] ok 8 zero[1] ok 9 first arg ok 10 second arg ok 11 third arg 1..11 # tests 11 # pass 11 # ok
and your test will run in chrome or firefox headlessly, depending which you have installed on your system. The console.log()
output is proxied from the browser to your stdout and the testling
command generates an exit code by parsing the TAP output.
Running a directory full of tape tests in a browser
To run multiple tests, just use a file glob:
$ browserify test/*.js | testling TAP version 13 # defined-or ok 1 empty arguments ok 2 1 undefined ok 3 2 undefined ok 4 4 undefineds ok 5 false[0] ok 6 false[1] ok 7 zero[0] ok 8 zero[1] ok 9 first arg ok 10 second arg ok 11 third arg # (anonymous) ok 12 should be equal 1..12 # tests 12 # pass 12 # ok
Running tape tests on Testling
To get your tape tests running on testling simply add the "testling" field to package.json
"testling" : { "files" : "test/*.js", "browsers" : { "ie" : [ 6, 7, 8, 9, 10 ], "ff" : [ 3.5, 10, 15.0, 16.0, 17.0 ], "chrome" : [ 10, 20, 21, 22, 23 ], "safari" : [ 5.1 ], "opera" : [ 10, 11, 12 ] } }
and setup a github hook to point to git.testling.com
. Now every time you push to github the tape tests will run in all the specified browsers.
To learn more about how to write testling tests, see this article.
Conclusion
If you need more complicated abstractions in your tests, just npm install
them and require()
them in your tests. Just be careful that the libraries you're importing also work in browsers.
Tape shows that you don't actually need very much API to test your libraries in a powerful and flexible way that works in node and in browsers.