BDD-style testing for QUnit.

BDD-style testing for QUnit.

describe('keys', function() {
  describe('.camelize', function() {
    it('camelizes top-level keys', function() {
      expect(camelize({ ohai_there: 'friend' })).to.eql({ ohaiThere: 'friend' });
    it('camelizes nested keys', function() {
      expect(camelize({ foo_bar: { bar_baz: 'baz' } }))
        .to.eql({ fooBar: { barBaz: 'baz' } });
    it('camelizes array objects', function() {
      expect(camelize([{ foo_bar: { bar_baz: 'baz' } }, { ohai_there: 'friend' }]))
        .to.eql([{ fooBar: { barBaz: 'baz' } }, { ohaiThere: 'friend' }]);
# Install via NPM.
$ npm install [--save-dev] qunit-bdd
# Install via Bower.
$ bower install [-D] qunit-bdd
# Install from Git.
$ git clone https://github.com/square/qunit-bdd.git
$ cp qunit-bdd/lib/qunit-bdd.js my-project/vendor/qunit-bdd.js

qunit-bdd has describe and context, just like Mocha and Jasmine. It also provides an assertion syntax similar to expect.js.

describe('Math', function() {
  describe('#pow', function() {
    it('raises the first argument to the power of the second argument', function() {
      expect(Math.pow(0, 6)).to.equal(0, '0**x == 0');
      expect(Math.pow(1, 99)).to.equal(1, '1**x == 1');
      expect(Math.pow(99, 0)).to.equal(1, 'x**0 == 1');
      expect(Math.pow(2, 3)).to.equal(8, 'positive exponent works');
      expect(Math.pow(4, -1)).to.equal(2, 'negative exponent works');

qunit-bdd also has before and after to run blocks of code before an after each test run within a context:

// This example uses sinon.js, not included with qunit-bdd. 
describe('Profile Page', function() {
  before(function() {
    this.alertStub = sinon.stub(window, 'alert');
  it('alerts on errors', function() {
    expect(this.alertStub.calledWith('UH OH!')).to.be.true();
  after(function() {

Additionally, qunit-bdd ships with support for RSpec-style per-context let values, called lazy values in qunit-bdd. This is very useful when you want to declare how to set up a complex object in a top-level context, overriding parts of that setup in nested contexts:

describe('Person', function() {
  lazy('person', function() {
    return new Person({
      firstName: this.firstName,
      lastName: this.lastName,
      dob: this.dob,
      address: this.address
  lazy('address', function() {
    return {
      street1: this.street1,
      street2: this.street2,
      city: this.city,
      state: this.state,
      postal: this.postal
  // Defaults for dependent values could be put here (e.g. firstName, street1, etc). 
  describe('#canVote', function() {
    context('when the person is not yet 18', function() {
      lazy('dob', function(){ return new Date(); });
      it('is false', function() {
    context('when the person is over 18', function() {
      lazy('dob', function(){ return new Date(0); });
      it('is true', function() {

The benefit to this approach over setting up your test objects in before is that you can override parts of the built objects declaratively in nested contexts, something you might have used a bunch of helper functions to do with QUnit's default module/test functions.

You can also use helper to define helper functions that have access to everything defined on the test context. This is useful for reusing a piece of code between tests that have different setups. Example:

describe('APIRequest', function() {
  before(function() {
    this.url = "http://api.endpoint.com";
    this.apiController = new ApiController();
    this.moreTestState = {};
  helper('fireApiRequest', function() {
    // full access to everything on current context. 
    this.apiController.ajax(this.url, this.moreTestState);
  it('works', function() {
    // ... test-specific setup 
  it('works in another context', function() {
    // ... test-specific setup 

It's still QUnit, so you can write some tests using the module/test style, complete with the usual ok/equal/deepEqual assertions, if you find it more appropriate sometimes. Also, you can export as much or as little of qunit-bdd to the global scope as you like:

// Turn off `lazy` and `context` exports. 
// Make sure to set this before loading qunit-bdd.js. 
    lazy: false,  // don't use lazy 
    expect: false // use the regular QUnit assertions (or another set altogether) 

By default your tests will run in the order in which they are defined. This is usually desirable for interactive development and debugging. But for continuous integration you may want to run your tests in a random order to reveal any hidden dependencies between your tests that may be causing them not to work as expected. To turn this on, set QUNIT_BDD_OPTIONS.randomize to true. Doing so will first shuffle your describes, then shuffle the its within.

If you want to use a particular randomizer, pass a function that takes an array and returns a shuffled array instead of true. For example, here's how to configure qunit-bdd to use chance.js with a random (but repeatable, for reproducing failures locally) seed:

var seed = Math.floor(Math.random() * 1000);
console.log('Random test order seed:', seed);
var chance = new Chance(seed);
  randomizefunction(array) {
    return chance.shuffle(array);

You can also configure which tests are run, which can aid in debugging. To skip a particular test (or context), use it.skip() instead of it() (or describe.skip() instead of describe()). To run only a particular test (or context), use it.only() instead of it (or describe.only() instead of describe()).

You can configure the built-in assertion expect() function to add your own custom assertions or override the built-in ones:

  // expect(2).to.be.even(); 
  evenfunction() {
    QUnit.ok(!(this._actual % 2), 'expected ' + this._actual + ' to be even');

Note that the expect() function can still be used as you would while writing QUnit tests the normal way, i.e. as expect(4) to set the number of expected assertions.

Come chat on our Google Group page or use the qunit-bdd tag on Stack Overflow.

First, install the development dependencies:

$ npm install

Then, try running the tests:

$ npm test

As you make changes you may find it useful to have everything automatically compiled and ready to test interactively in the browser. You can do that using the develop script:

$ npm run develop

Then go to http://localhost:8000/test in your browser (run with PORT={port} to override the default port).

Contributions via pull requests are very welcome! Follow the steps in Developing above, then add your feature or bugfix with tests to cover it, push to a branch, and open a pull request.

Any contributors to the master qunit-bdd repository must sign the Individual Contributor License Agreement (CLA). It's a short form that covers our bases and makes sure you're eligible to contribute.

When you have a change you'd like to see in the master repository, send a pull request. Before we merge your request, we'll make sure you're in the list of people who have signed a CLA.