Skip to content
This repository


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Doctests for JavaScript and CoffeeScript

tag: 0.4.0

Fetching latest commit…


Cannot retrieve the latest commit at this time

Octocat-spinner-32 bin
Octocat-spinner-32 lib
Octocat-spinner-32 src
Octocat-spinner-32 test
Octocat-spinner-32 LICENSE 0.4.0 December 08, 2012
Octocat-spinner-32 Makefile
Octocat-spinner-32 README.markdown
Octocat-spinner-32 package.json


Doctests are executable usage examples sometimes found in "docstrings". JavaScript doesn't have docstrings, but inline documentation can be included in code comments. doctest executes usage examples in JavaScript/CoffeeScript comments to verify that one's code and inline documentation are in agreement.

# Math.product
# ------------
# Return the product of two or more numeric values:
#     > Math.product -2, 2.5, "3"
#     -15
# `NaN` is returned if the values cannot all be coerced to numbers:
#     > Math.product 2, "ten"
#     NaN
# `undefined` is returned if fewer than two values are provided:
#     > Math.product 100
#     undefined
Math.product = (numbers...) ->
  return unless numbers.length
  product = 1
  product *= number for number in numbers

Doctests needn't be indented, though there's no harm in being Docco-friendly.

Running doctests

To run doctests, pass doctest paths to one or more "modules" to be tested. Doctests can be run from the command line or from a browser console: provide local file system paths in the former case, URLs in the latter. Specifically, each URL should be one of the following:

For example:

> doctest("../src/")
retrieving /scripts/lib/../src/
running doctests in
expected undefined on line 17 (got 100)

Oops. Looks like we have a disagreement.


It's easy to indicate that an error (of a particular kind) is expected:

// > null.length
// TypeError


doctest doesn't use a parser; it treats JavaScript files as lines of text. In spite of this, each doctest has access to variables in its scope chain:

!function() {

  var x = 6
  var y = 7
  // > x * y
  // 42


It's even possible to reference variables that have not yet been defined:

!function() {

  // > toUsername("Jesper Nøhr")
  // "jespernhr"
  // > toUsername(15 * 15)
  // "225"
  var toUsername = function(text) {
    return ('' + text).replace(/\W/g, '').toLowerCase()


It's important to be familiar with the hack doctest employs to achieve this, since it places constraints on where doctests may appear in a file.

Once doctest has retrieved a file via XMLHttpRequest, three things happen:

  1. Input lines (single-line comments beginning with ">") and associated output lines are rewritten as executable code (calls to doctest.input and doctest.output, specifically).

  2. The rewritten file is eval'd.

  3. is called, invoking functions queued in the previous step.

In the first step, the code example above would be rewritten as:

!function() {

  doctest.input(function() {
    return toUsername("Jesper Nøhr")
  doctest.output(4, function() {
    return "jespernhr"
  doctest.input(function() {
    return 15 * 15
  doctest.output(6, function() {
    return "225"
  var toUsername = function(text) {
    return ('' + text).replace(/\W/g, '').toLowerCase()


The naive nature of the rewriter prevents this from working:

MyApp.utils = {
  // >
  // "foo"
  foo: function() {
    return 'foo'
  // >
  // "bar"
  bar: function() {
    return 'bar'

The code could be restructured to accommodate the rewriter:

MyApp.utils = {}

// >
// "foo" = function() {
  return 'foo'

// >
// "bar" = function() {
  return 'bar'


The following libraries are required to run doctests from a browser console:

Running the test suite

make setup
make test

This runs doctest's test suite: first headless, then in a browser.

Something went wrong with that request. Please try again.