Better Unit Testing with Tape

Unit tests are very useful in improving the overall quality of your codebase by allowing you to test each unit of your application. A unit could be a function, component, or object that can be tested separately from the rest of your application. Having unit tests enforces you to write testable code and break down your codebase into smaller modular pieces.

Tape is a Node test library that allows you to easily write unit tests for Node and browsers. Unlike other test frameworks such as Mocha, Jasmine, or Jest, it does not require too much configuration to run your tests and can be easily integrated with other node packages and Unix command line tools.

I've switched to using Tape testing library early this year, and found it to be a simpler and better solution for writing unit tests in JavaScript.

The Problem with Existing Test Frameworks

I have used several testing frameworks in past projects such as Mocha, QUnit, and Jasmine, and they require a significant amount of boilerplate code and configuration to use them. You would also need to choose an assertion library, such as Chai, and then choose a test runner such as Gulp or Grunt. This is quite cumbersome and consumes precious time just to setup properly. Even more problematic is when you use Mocha to run your tests on browsers. It's quite difficult to access the files you want tested.

Current popular testing frameworks also have a lot of global functions that litters the global namespace with functions like - assert, beforeEach, describe, etc. This is contradictory to best coding practices which encourages you to avoid using globals as much as possible.

TAP Protocol and Tape

Tape uses TAP, or Test Anything Protocol, a standard for displaying test output. It has been around since 1987 and implemented in many languages. The TAP protocol output looks like the following:

TAP version 13  
  # Unit Tests
  ok 1 filter() should return the results as expected
  ok 2 map() should return the results as expected
  ok 3 reduce() should summarise list total
  # tests 10
  # pass 10
  # fail 0
  ok 1 Test was run
  # TAP meta information
  0 errors

Tape displays test results in TAP, an easy to read format and can be easily integrated with other command line tools and node packages. Since TAP is widely supported, there are many tools available to process the TAP output into other display formats. It also allows you to run tests on your files directly and can run both on Node and browsers.

Technically, tape is just a command line tool that takes tests as input and returns TAP format as output. This means that you can use any Unix command tool available in Node, and integrate it with other tools that can read from standard input and understand TAP output.

Running Tape in Node

Running tape tests in node is simple and easy. You just need to add require('tape') in your test file and run the following command just like any other Node script:

node tests/test.js  

There's no need for additional test runner script just to run your tests like in Mocha or Jasmine. Just run the test file with the node command and you're done.

Running Tape in Browsers

If you need to run tests on browsers, all you need to do is use browserify to bundle your tests, and just write it to an index.html file and open it in the browser:

$ browserify tests/*.js > test_bundle.js
<!-- index.html -->  
<script src="test_bundle.js"></script>  

Open the index.html file in your browser and see the TAP output in the console.

Final Words

As of this writing, tape is by far the simplest and most flexible test library for JavaScript that can both run on Node and browsers. Using tape lets you concentrate more on building your application, and prevents you from spending too much time in writing unit tests. Having the ability to run tests directly from the command line without too much need for configuration is very convenient. The flexibility of tape allows you to write better unit tests that prevent bugs and improve your overall code design.

Tape lets you run tests very easily on Node and browsers since it utilizes the console.log() and standard output interfaces. This allows you to process the output further using Unix command line tools and easily integrate with continuous integration services. Having these features is very helpful in writing JavaScript code that suits your specific requirements.