node package manager


A light-weight RSpec-esque testing framework

======== nodespec

.. image::

A light-weight RSpec_-esque testing framework designed and built specifically for NodeJS.

.. _RSpec:

.. contents:: :local:


  • Ground-up support for NodeJS convention callbacks

  • Only one test running at a time

  • No global variables

  • RSpec style syntactic sugar

    • Nested contexts
    • Easy to use setup/teardown
    • Subject helpers
  • Pluggable mocking support

  • Native assertions

  • Easy to extend or replace the default assertions

  • Multiple output formatters on the same test run (not yet implemented)


README Driven Development_ Any and all features will be outlined in this readme file before the tests are written.

BEHAVIOUR Driven Development Integration tests which treat the executable as a black-box will be written using cucumber_ & aruba_ (yes, using Ruby) before any implementation.

Lots and lots of Unit Tests All code will be fully unit tested using NodeSpec itself before release.

.. _README Driven Development: .. _cucumber: .. _aruba:

If you'd like to contribute

  1. Fork the repository on github
  2. Make your changes
  3. Run the unit tests
  4. Run the cucumber tests with cucumber -p all
  5. Push back to github and send me a pull request

If you're fixing a bug, please add a testcase to prove it was broken and is fixed, if you're adding a new feature, please add cucumber feature file for it.

To be able to run cucumber, you'll need Ruby and Bundler installed, then do bundle install.


Via npm::

npm install nodespec

Or clone directly from github::

git clone git://
cd nodespec
npm link


Require the module into test files to use it::

var nodespec = require('nodespec');

And then at the end of each test file::


Simple spec::

nodespec.describe("Addition", function() {
    this.example("1 + 1 = 2", function() {
        this.assert.equal(1 + 1, 2);

Simple async spec::

nodespec.describe("nextTick", function() {
    // Accept 1 argument in the definition for an async test
    this.example("fires the callback", function(test) {
        this.assert.strictEqual(this, test);
        process.nextTick(function() {
            this.assert.strictNotEqual(this, test);
            // async tests must call test.done()

Before/After Hooks::

// Hooks share `this` with tests, but it's rebuilt each time
nodespec.describe("Some databasey test", function() {
    this.before(function(hook) {
        this.assert.strictEqual(this, hook);
        db_connect(function (err, conn) {
            hook.db = conn;
            hook.db.start_transaction(function(err, tx) {
                hook.tx = tx;
    this.after(function() {
    this.example("database interaction", function(test) {
        test.db.insert({field: 1}, function(err, result) {
            test.assert.strictEqual(result.affected, 1);
            test.db.get(function(err, result) {
                test.assert.strictEqual(result.field, 1);

Nested contexts with subject::

nodespec.describe("My Server", function() {
    // This function is executed once when `this.server` is accessed
    this.subject('server', function() {
        return new Server(1337);
    this.context("Strict Mode", function() {
        this.before(function() {
        this.example("invalid request fails", function(test) {
            test.server.request('invalid', function(err, result) {
                test.assert.notEqual(err, null);
    this.context("Not Strict Mode", function() {
        this.before(function() {
        this.example("invalid request fails silently", function(test) {
            test.server.request('invalid', function(err, result) {
                test.assert.equal(err, null);
                test.assert.equal(result, null);


Copyright © 2011 The NodeSpec Authors. See LICENSE and AUTHORS for details.