- tape is still great and recommended for many projects.
- tap is more actively maintained and has better support for code coverage and built-in pretty reporters. It includes those things at the cost of not supporting browsers, and being a bigger dependency.
- I also use Jest often because it has good support for JSDom "browser-like" testing and integration with Babel for testing ES2017.
What it sorts down into is roughly three parts: the protocol, browserify, and magic.
The Test Anything Protocol
TAP, or the Test Anything Protocol is the definition of ‘tried & true’: it’s been around since 1987 and has been implemented in a ton of languages. It’s just a dead-simple way to format test results, like
Having this format be super simple means that you can combine tools that have common expectations. For instance, faucet is a node module that gives pretty, summarized results for your tests, but it doesn’t directly plug into
node-tap - all it cares about is the TAP protocol, so you can pipe results into it. You could even pipe a TAP producer in a different language into it, and it’ll work just the same.
browserify is another awesome tool written by substack. With it, you can use node-style
require() calls in code you’re going to run in browsers, and then use the
browserify command to stitch them all together and make something you can throw in a script tag.
Browserify has been huge for writing cross-platform libraries, and it’s been huge for building things. Mapbox.com and Mapbox.js are both constructed this way - individual libraries on npm,
package.json just like nodejs code, and then browserify to bring it to the web.
Long story short,
browserify ‘just works’ with
mocha has something of an unusual browser story - it’s hard to get at the files you’d want to run tests in a browser, and then when you do, if you want to run tests in both browsers and node, it’s not straightforward to conditionally require things sometimes.
So, to run browserify tests in a browser, you can just run
console.log to write its results, which is super easy to pull out of a headless browser.
So, we’ve discussed TAP a little bit, and you might notice that mocha supports TAP too. So why not just use mocha to write tests? Let’s talk about that.
Mocha does a little magic. With only few exceptions, nodejs has the assumption that any variables on a page will come from obvious places:
In the interest of simplicity,
mocha doesn’t follow this rule. Your mocha test files have assumptions:
Keen eyes will notice that
assert entered the stage by a
require() call, but
it didn’t - they appear magically.
On the other hand, a basic
test comes from
t comes from the closure. Simple enough. This lack of abstraction has two awesome advantages:
- It’s easier to form a mental model of what’s going on, so it’s easier to hack with it and know what’ll happen. What if I call a function with
tand then call functions off of
t? It’ll work.
- Tests are code. So, you can run tests as modules with node, just like you’d run other code:
node test/test.js, and it works. As opposed to needing a ‘test runner’ binary that contains some of the code the test really needs.
Testling & Travis-CI
Continuous Integration, where every commit to GitHub is automatically tested, has become a necessity. Setting the green ‘this works’ badge on projects means something, and we’ve found that running tests on remote hosts can give a better sanity check than just running them locally - the environment is constructed from scratch, there aren’t any stray files that make things work.
tape works with testling just like mocha - the same minimal
.travis.yml file ‘just works’ as long as
npm install and
npm test do their things. But on top of that, you can use Testling-CI and testling, and test commits in browsers. Testling-CI works the same as Travis: set a webhook, tweak a few package.json properties, and you’ll get a page of your own with results. testling, on the other hand, runs headless tests locally, with your real browsers, not with phantomjs or another custom abstraction. In combination, this means that you can easily cross-browser test code. And if the abstractions break, it’s easy to just
browserify the code and run the tests manually.