--- layout: home ---

Documentation


Syntax Overview

The Basics

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

These are the basic building blocks of foounit and asynchronous BDD style testing.

it (aka example)

In BDD speak an it block is an example that defines usage of a particular 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);
});
  

So you might think that an it block is overkill for a test like this, but also realize that this is a contrived example. The nice thing about using it is that you are able to label this test with a description for the next developer that touches this code.

If you just want to play around with foounit to get an idea for how this will work, you can run something like this. 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. All ths really means to you is that describe actually defines a particular behavior. Let me explain...

Let's say you have a signup form widget that allows you to 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 might 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 also 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 (){
    ...
  });
});
  

expect (aka assertion)

The expect keyword is just another way of creating an assertion. An assertion is a way to test that a particular value is what you expect that it should 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 something that sets up a particular test. A before block is run once for each group and they can be nested. before blocks are great for asserting that a test is setup properly before an example is run and for removing clutter from your tests. before blocks can be nested within describes and are run in order for each example.

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's great for cleaning up the environment and it runs even when the test 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 asynchronousness if you are just experimenting. If anything in this guide is unclear, then please email the group.



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 particular 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 to be called. 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 yourself 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 also 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 against 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