--- layout: home ---

Documentation

Hopefully these docs help you out, but if they don't then please file a bug. Documentation bugs will be treated with high priority.


Syntax Overview

The Basics

The main keywords in foounit are:
describe, it, before, after, expect, mock
There's another class of foounit keywords for asynchronous testing, but these are explained in the async awesomeness section.
waitFor, run, waitForTimeout

it (aka example)

In BDD-speak an it block is an example that defines usage of a feature. So let's say we want to test that a string is less than 10 characters. You might create an it block that looks like this:

it('returns true', function (){
  var str = "sml_string";

  // expect is assertion... don't worry about this for now, but this test will pass
  expect(str.length < 10).to(beTrue);
});
  

You might think that an it block is overkill for a test like this, but this is a contrived example. The nice thing about using an it block is that you can provide documentation for the next developer working on the code.

If you want to experiment, you can try this example. Create a file called test.js with this code:

var foounit = require('foounit').globalize();

it('fails the test', function (){
  expect(true).to(beFalse);
});

foounit.run();
  
Then run the file with this command:
$ node test.js

This test will fail, but it will give you an idea of what happens when you run an example.

describe (aka group)

Internally, describe creates a group of examples. describes describe a group of related behavior.

Let's say you have a signup form widget that lets you submit a form when you have a password that is 8 or more characters, but it shows an error message if you have password that is less than 8 characters. You'll have a test that looks like this:

describe('when the password is 8 or more characters', function (){
  it('allows you to submit the form', function (){
    ...
  });
});

describe('when the password is less than 8 characters', function (){
  it('displays an error message', function (){
    ...
  });
});
  

You can nest describes if your code has nested behaviors (or nested if statements). Nested describes look something like this:

describe('when foo is not falsy', function (){
  describe('when foo is an integer', function (){
    it('returns true', function (){
      ...
    });
  });

  describe('when foo is a boolean', function (){
    it('returns false', function (){
      ...
    });
  });
});

describe('when foo is falsy', function (){
  it('returns false', function (){
    ...
  });
});
  

xdescribe (aka group)

Creates a pending group. All groups and examples nested within a pending group will be marked as pending. This can be used to mark an entire set of tests as pending.

xdescribe('example group', function (){
  it('runs some test', function (){   // This example will be marked as pending and will not run
    ...
  });
});

expect (aka assertion)

The expect keyword creates an assertion. An assertion tests that a value is the value you expect it to be. Here is a breakdown of how expect works:

expect(
  foo    // actual value
).to(
  be     // this is a === matcher... more on this later
  , 100  // expected value
);
  

Here are some additional example expectations:

expect(1).to(beLt, 2);            // passes
expect(true).to(beFalse);         // fails
expect([1,2,3]).to(include, 2);   // passes
  

Here are some examples of expectations that assert actual and expected do not match:

expect(1).toNot(be, 2);           // passes
expect(function (){
  throw new Error('errar!');
}).toNot(throwError);             // fails
  

before (aka setup)

A before block is a function that sets up a test. A before block is run once for each group, and it can exist within nested groups. before blocks are great for asserting that a test is setup properly before an example runs, and they remove clutter from your tests. Nested groups will run before blocks in the order in which the groups are nested.

describe('when foo is 1', function (){
  var foo;

  before(function (){                       // runs first
    foo = 1;
  });

  it('does something', function (){
    ...
  });

  describe(when foo is 2', function (){
    before(function (){                     // runs second
      foo++;
      expect(foo).to(be, 2);
    });

    it('does another thing', function (){
      ...
    });
  });
});
  

after (aka teardown)

after runs after each test. It should be used for cleaning up the previous test and it runs regardless of whether the example passes or fails.

Here is how to use before and after in conjunction to cleanup global variables:

describe('when the current user is bob', function (){
  var origUser;

  before(function (){
    origUser = global.currentUser;        // save off currentUser
    global.currentUser = 'bob';
  });

  after(function (){
    global.currentUser = origUser;        // reset currentUser after the test runs
  });

  it('does something', function (){
    ...
  });
});
  

These keywords are 90% of what you need to write tests in BDD-style using foounit. There is a lot more to foounit than just these keywords but you can get by without learning about additional matchers and asynchronous testing if you are just experimenting.



Async Awesomeness

foounit is a fully asynchronous test runner. When a foounit example is created, it runs an asynchronous execution queue so all tests are asynchronous by default. Each asynchronous keyword adds an item to the queue and does not run until the previous task has completed.

waitFor

There are many cases in which you may want to wait for an asynchronous event to finish before passing or failing a test. The waitFor keyword will poll until a expectation has been met or a timeout occurs. Here is an example:
var successCallback;

before(function (){
  successCallback = mock(function (data){});
  $.ajax('http://localhost:5057/data.json', { success: successCallback });
});

it('gets the data', function (){
  waitFor(function (){
    expect(successCallback).to(haveBeenCalled);
  });
});

In this example, an xhr request is made to get the JSON data at http://localhost:5057/data.json. We have mocked the success callback and we wait for the response to succeed and call our callback. If the request succeeds then the test will pass, but if the request is unsuccessful then the test will fail. The waitFor keyword waits for the function it is passed to run without failing. If the waitFor block fails, then it is retried until a timeout is reached. If the timeout is reached then the test fails and a kitten dies.

run

There's more to asynchronous testing than just waitFor but waitFor will generally get you pretty far. Another common use-case is to wait for an expectation to be met, then do something else and wait for another expectation. In this case you can use run to insert a block into foounit's asynchronous execution queue. Here is an example:

it('does a lot of async stuff', function (){
  var foo = '';

  setTimeout(function (){ foo = 'bar'; }, 200);

  // Waits for foo to become 'bar'
  waitFor(function (){ expect(foo).to(be, 'bar'); });

  // Runs after the waitFor above
  run(function (){
    setTimeout(function (){ foo = 'baz'; }, 200);
  });

  // Waits for foo to become 'baz'
  waitFor(function (){ expect(foo).to(be, 'baz'); });
});

waitForTimeout

foounit can assert that something never happens with the use of waitForTimeout. These kinds of tests are generally frowned upon because they slow down a test suite, but sometimes they are valuable enough to offset the downside of slowing down the test suite.

waitForTimeout will run a function until a timeout is reached. The first time the function passes without error, waitForTimeout fails. Consider this example:

it('doesnt get to 1000 fast enough', function (){
  var foo = 0
    , inc = function (){ foo++; setTimeout(inc, 200); }

  setTimeout(inc, 200);

  waitForTimeout(function (){
    expect(foo).to(beGt, 999);
  });
});

This example will fail because foo will not reach 1000 in the time that it takes for waitForTimeout to timeout.



Matchers

be

Asserts that actual === expected.

expect(1).to(be, 1);                // passes
expect(undefined).to(be, null);     // fails

beGt

Assert that actual is greater than expected.

expect(5).to(beGt, 4);              // passes 
expect(1).to(beGt, 2);              // fails

beFalse

Assert that actual is === false.

expect(false).to(beFalse);          // passes 
expect(null).to(beFalse);           // fails

beFalsy

Assert that actual is falsy.

expect(false).to(beFalsy);          // passes 
expect(null).to(beFalsy);           // passes
expect("test").to(beFalsy);         // fails

beLt

Assert that actual is less than expected.

expect(1).to(beLt, 2);              // passes 
expect(5).to(beLt, 4);              // fails

beNull

Asserts that actual === null.

expect(null).to(beNull);            // passes
expect(undefined).to(beNull);       // fails

beTruthy

Asserts that actual is truthy.

expect(1).to(beTruthy);             // passes
expect('').to(beTruthy);            // fails
expect(true).to(beTruthy);          // passes

beUndefined

Asserts that actual === undefined.

expect(null).to(beUndefined);       // fails
expect(undefined).to(beUndefined);  // passes

equal

Assert that actual is deeply equal to expected. This is useful for saying that one object is the same as another but they are referencing different objects.

expect({ foo: ['bar'] }).to(equal, { foo: ['bar'] });   // passes
expect({ baz: 1 }).to(equal, { baz: 2 });               // fails

include

Assert that an array has an element that matches type and object equality of expected.

expect([1, 2, 3]).to(include, 2);   // passes
expect([1, 2, 3]).to(include, 10);  // fails

match

Assert that actual matches a regex.

expect('foo bar baz').to(match, /bar/);   // passes
expect('foo bar baz').to(match, /qux/);   // fails

throwError

Asserts that the a function throws an error. The error message can be matched with a regex to assert that the correct error message was thrown.

expect(function (){ throw new Error(); }).to(throwError);                       // passes
expect(function (){ throw new Error('HEY NOW'); }).to(throwError, /Fuuuuuu/);   // fails
expect(function (){ /** I don't throw **/ }).to(throwError);                    // fails

Suites

TODOC

Loading files

TODOC