Getting started

In this tutorial you’ll learn how to write your first tests using jstest and how to run them in the browser. Let’s start by writing a spec for some code we want to write, say, an implementation of the Set data structure. This class must be able to store a unique collection of strings and tell us whether a string is in the set or not.

Let’s start by creating a few directories to hold our project (this mirrors the structure of the jstest GitHub repo if you want to download the finished example). Download jstest and save it into the build/ directory, and create the following directories:

build/
    jstest.js
example/
    browser.html
    lib/
        set.js
    spec/
        set_spec.js

Writing a spec

We’ll write a spec for our project in spec/set_spec.js. A spec begins with a call to JS.Test.describe(), with the tests nested inside.

// example/spec/set_spec.js

JS.Test.describe('Set', function() { with(this) {
  before(function() { with(this) {
    this.set = new Set(['foo'])
  }})

  describe('hasMember', function() { with(this) {
    it('returns true for members', function() { with(this) {
      assert( set.hasMember('foo') )
    }})

    it('returns false for non-members', function() { with(this) {
      assertNot( set.hasMember('bar') )
    }})
  }})
}})

Setting up a test page

We’ve written a simple spec for one method in our class, now we need a way to run it. To do this, make a page in browser.html containing the following code. All it does it load jstest, our code, and our tests, and tell JS.Test to run the test suite:

<!-- example/browser.html -->

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>jstest</title>
  </head>
  <body>

    <script src="../build/jstest.js"></script>
    <script src="./lib/set.js"></script>
    <script src="./spec/set_spec.js"></script>

    <script>
      JS.Test.autorun()
    </script>

  </body>
</html>

If you don’t like wrangling script tags, you can use any module loader you like; jstest doesn’t care how your code gets loaded.

If you open this page in your browser you’ll see something like this. If you click the names of the tests to expand them you can see why each one failed.

Making the tests pass

Okay, looks like Set is not defined, which makes sense – we’ve not written any code yet. So let’s add the following to lib/set.js to remove the error:

// example/lib/set.js

var Set = function() {}

If we reload the tests we have a different error this time:

A bit better, we just need to add the missing method. Let’s add the smallest amount of code to make this error go away:

// example/lib/set.js

var Set = function() {}

Set.prototype.hasMember = function() {
  return true
}

This has made one of the tests pass, but one is still broken:

Finally, let’s implement the logic we really need to make the tests pass:

// example/lib/set.js

var Set = function(members) {
  this._members = {}
  for (var i = 0, n = members.length; i < n; i++) {
    this._members[members[i]] = true
  }
}

Set.prototype.hasMember = function(value) {
  return this._members.hasOwnProperty(value)
}

At last, when we reload the page we see all the tests have passed: