Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

Latest Update to Github

Loading...
Loading...

BDD Style Introduction

The BDD style is exposed through expect or should interfaces. In both
scenarios, you chain together natural language assertions.

 // expect
 var expect = require('chai').expect;
 expect(foo).to.equal('bar');

 // should
 var should = require('chai').should();
 foo.should.equal('bar');

Differences

The expect interface provides a function as a starting point for chaining
your language assertions. It works on node.js and in all browsers.

The should interface extends Object.prototype to provide a single getter as
the starting point for your language assertions. It works on node.js and in
all browsers except Internet Explorer.

Configuration

By default, Chai does not show stack traces upon an AssertionError. This can
be changed by modifying the includeStack parameter for chai.Assertion. For example:

 var chai = require('chai');
 chai.Assertion.includeStack = true; // defaults to false

to

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'to',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

be

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'be',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

been

@apipublic

Language chain. Also tests tense to past for addon
modules that use the tense feature.

View Source
Object.defineProperty(Assertion.prototype, 'been',
  { get: function () {
      this.tense = 'past';
      return this;
    }
  , configurable: true
});
            

an

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'an',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

is

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'is',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

and

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'and',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

have

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'have',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

with

@apipublic

Language chain.

View Source
Object.defineProperty(Assertion.prototype, 'with',
  { get: function () {
      return this;
    }
  , configurable: true
});
            

.not

@apipublic

Negates any of assertions following in the chain.

View Source
Object.defineProperty(Assertion.prototype, 'not',
  { get: function () {
      this.negate = true;
      return this;
    }
  , configurable: true
});
            

.ok

@apipublic

Assert object truthiness.

 expect('everthing').to.be.ok;
 expect(false).to.not.be.ok;
 expect(undefined).to.not.be.ok;
 expect(null).to.not.be.ok;
View Source
Object.defineProperty(Assertion.prototype, 'ok',
  { get: function () {
      this.assert(
          this.obj
        , 'expected ' + this.inspect + ' to be truthy'
        , 'expected ' + this.inspect + ' to be falsy');

      return this;
    }
  , configurable: true
});
            

.true

@apipublic

Assert object is true

View Source
Object.defineProperty(Assertion.prototype, 'true',
  { get: function () {
      this.assert(
          true === this.obj
        , 'expected ' + this.inspect + ' to be true'
        , 'expected ' + this.inspect + ' to be false'
        , this.negate ? false : true
      );

      return this;
    }
  , configurable: true
});
            

.false

@apipublic

Assert object is false

View Source
Object.defineProperty(Assertion.prototype, 'false',
  { get: function () {
      this.assert(
          false === this.obj
        , 'expected ' + this.inspect + ' to be false'
        , 'expected ' + this.inspect + ' to be true'
        , this.negate ? true : false
      );

      return this;
    }
  , configurable: true
});
            

.exist

@apipublic

Assert object exists (null).

 var foo = 'hi'
   , bar;
 expect(foo).to.exist;
 expect(bar).to.not.exist;
View Source
Object.defineProperty(Assertion.prototype, 'exist',
  { get: function () {
      this.assert(
          null != this.obj
        , 'expected ' + this.inspect + ' to exist'
        , 'expected ' + this.inspect + ' to not exist'
      );

      return this;
    }
  , configurable: true
});
            

.empty

@apipublic

Assert object's length to be 0.

 expect([]).to.be.empty;
View Source
Object.defineProperty(Assertion.prototype, 'empty',
  { get: function () {
      var expected = this.obj;

      if (Array.isArray(this.obj)) {
        expected = this.obj.length;
      } else if (typeof this.obj === 'object') {
        expected = Object.keys(this.obj).length;
      }

      this.assert(
          !expected
        , 'expected ' + this.inspect + ' to be empty'
        , 'expected ' + this.inspect + ' not to be empty');

      return this;
    }
  , configurable: true
});
            

.arguments

@apipublic

Assert object is an instanceof arguments.

 function test () {
   expect(arguments).to.be.arguments;
 }
View Source
Object.defineProperty(Assertion.prototype, 'arguments',
  { get: function () {
      this.assert(
          '[object Arguments]' == Object.prototype.toString.call(this.obj)
        , 'expected ' + this.inspect + ' to be arguments'
        , 'expected ' + this.inspect + ' to not be arguments'
        , '[object Arguments]'
        , Object.prototype.toString.call(this.obj)
      );

      return this;
    }
  , configurable: true
});
            

.equal(value)

Assertion.prototype.equal()

@param{ * }value
@apipublic

Assert strict equality.

 expect('hello').to.equal('hello');
View Source
Assertion.prototype.equal = function (val) {
  this.assert(
      val === this.obj
    , 'expected ' + this.inspect + ' to equal ' + inspect(val)
    , 'expected ' + this.inspect + ' to not equal ' + inspect(val)
    , val );

  return this;
};
            

.eql(value)

Assertion.prototype.eql()

@param{ * }value
@apipublic

Assert deep equality.

 expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
View Source
Assertion.prototype.eql = function (obj) {
  this.assert(
      eql(obj, this.obj)
    , 'expected ' + this.inspect + ' to equal ' + inspect(obj)
    , 'expected ' + this.inspect + ' to not equal ' + inspect(obj)
    , obj );

  return this;
};
            

.above(value)

Assertion.prototype.above()

@param{ Number }value
@apipublic

Assert greater than value.

 expect(10).to.be.above(5);
View Source
Assertion.prototype.above = function (val) {
  this.assert(
      this.obj > val
    , 'expected ' + this.inspect + ' to be above ' + val
    , 'expected ' + this.inspect + ' to be below ' + val);

  return this;
};
            

.below(value)

Assertion.prototype.below()

@param{ Number }value
@apipublic

Assert less than value.

 expect(5).to.be.below(10);
View Source
Assertion.prototype.below = function (val) {
  this.assert(
      this.obj < val
    , 'expected ' + this.inspect + ' to be below ' + val
    , 'expected ' + this.inspect + ' to be above ' + val);

  return this;
};
            

.within(start, finish)

Assertion.prototype.within()

@param{ Number }startlowerbound inclusive
@param{ Number }finishupperbound inclusive
@apipublic

Assert that a number is within a range.

 expect(7).to.be.within(5,10);
View Source
Assertion.prototype.within = function (start, finish) {
  var range = start + '..' + finish;

  this.assert(
      this.obj >= start && this.obj <= finish
    , 'expected ' + this.inspect + ' to be within ' + range
    , 'expected ' + this.inspect + ' to not be within ' + range);

  return this;
};
            

.a(type)

Assertion.prototype.a()

@param{ String }type
@apipublic

Assert typeof.

 expect('test').to.be.a('string');
View Source
Assertion.prototype.a = function (type) {
  var klass = type.charAt(0).toUpperCase() + type.slice(1);

  this.assert(
      '[object ' + klass + ']' === toString.call(this.obj)
    , 'expected ' + this.inspect + ' to be a ' + type
    , 'expected ' + this.inspect + ' not to be a ' + type
    , '[object ' + klass + ']'
    , toString.call(this.obj)
  );

  return this;
};
            

.instanceof(constructor)

Assertion.prototype.instanceof()

@param{ Constructor }
@aliasinstanceOf
@apipublic

Assert instanceof.

 var Tea = function (name) { this.name = name; }
   , Chai = new Tea('chai');

 expect(Chai).to.be.an.instanceOf(Tea);
View Source
Assertion.prototype.instanceof = function (constructor) {
  var name = constructor.name;
  this.assert(
      this.obj instanceof constructor
    , 'expected ' + this.inspect + ' to be an instance of ' + name
    , 'expected ' + this.inspect + ' to not be an instance of ' + name);

  return this;
};
            

.property(name, [value])

Assertion.prototype.property()

@param{ String }name
@param{ * }value(optional)
@returnsvalue of property for chaining
@apipublic

Assert that property of name exists, optionally with value.

 var obj = { foo: 'bar' }
 expect(obj).to.have.property('foo');
 expect(obj).to.have.property('foo', 'bar');
 expect(obj).to.have.property('foo').to.be.a('string');
View Source
Assertion.prototype.property = function (name, val) {
  if (this.negate && undefined !== val) {
    if (undefined === this.obj[name]) {
      throw new Error(this.inspect + ' has no property ' + inspect(name));
    }
  } else {
    this.assert(
        undefined !== this.obj[name]
      , 'expected ' + this.inspect + ' to have a property ' + inspect(name)
      , 'expected ' + this.inspect + ' to not have property ' + inspect(name));
  }

  if (undefined !== val) {
    this.assert(
        val === this.obj[name]
      , 'expected ' + this.inspect + ' to have a property ' + inspect(name) + ' of ' +
          inspect(val) + ', but got ' + inspect(this.obj[name])
      , 'expected ' + this.inspect + ' to not have a property ' + inspect(name) + ' of ' +  inspect(val)
      , val
      , this.obj[val]
    );
  }

  this.obj = this.obj[name];
  return this;
};
            

.ownProperty(name)

Assertion.prototype.ownProperty()

@aliashaveOwnProperty
@param{ String }name
@apipublic

Assert that has own property by name.

 expect('test').to.have.ownProperty('length');
View Source
Assertion.prototype.ownProperty = function (name) {
  this.assert(
      this.obj.hasOwnProperty(name)
    , 'expected ' + this.inspect + ' to have own property ' + inspect(name)
    , 'expected ' + this.inspect + ' to not have own property ' + inspect(name));
  return this;
};
            

.length(val)

Assertion.prototype.length()

@aliaslengthOf
@param{ Number }length
@apipublic

Assert that object has expected length.

 expect([1,2,3]).to.have.length(3);
 expect('foobar').to.have.length(6);
View Source
Assertion.prototype.length = function (n) {
  new Assertion(this.obj).to.have.property('length');
  var len = this.obj.length;

  this.assert(
      len == n
    , 'expected ' + this.inspect + ' to have a length of ' + n + ' but got ' + len
    , 'expected ' + this.inspect + ' to not have a length of ' + len
    , n
    , len
  );

  return this;
};
            

.match(regexp)

Assertion.prototype.match()

@param{ RegExp }RegularExpression
@apipublic

Assert that matches regular expression.

 expect('foobar').to.match(/^foo/);
View Source
Assertion.prototype.match = function (re) {
  this.assert(
      re.exec(this.obj)
    , 'expected ' + this.inspect + ' to match ' + re
    , 'expected ' + this.inspect + ' not to match ' + re);

  return this;
};
            

.include(obj)

Assertion.prototype.include()

@param{ Object | String | Number }obj
@apipublic

Assert the inclusion of an object in an Array or substring in string.

 expect([1,2,3]).to.include(2);
View Source
Assertion.prototype.include = function (obj) {
  this.assert(
      ~this.obj.indexOf(obj)
    , 'expected ' + this.inspect + ' to include ' + inspect(obj)
    , 'expected ' + this.inspect + ' to not include ' + inspect(obj));

  return this;
};
            

.string(string)

Assertion.prototype.string()

@param{ String }string
@apipublic

Assert inclusion of string in string.

 expect('foobar').to.have.string('bar');
View Source
Assertion.prototype.string = function (str) {
  new Assertion(this.obj).is.a('string');

  this.assert(
      ~this.obj.indexOf(str)
    , 'expected ' + this.inspect + ' to contain ' + inspect(str)
    , 'expected ' + this.inspect + ' to not contain ' + inspect(str));

  return this;
};
            

contain

@apipublic

Toggles the contain flag for the keys assertion.

View Source
Object.defineProperty(Assertion.prototype, 'contain',
  { get: function () {
      this.contains = true;
      return this;
    },
    configurable: true
});
            

.keys(key1, [key2], [...])

Assertion.prototype.keys()

@aliaskey
@param{ String | Array }Keys
@apipublic

Assert exact keys or the inclusing of keys using the contain modifier.

 expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
 expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
View Source
Assertion.prototype.keys = function(keys) {
  var str
    , ok = true;

  keys = keys instanceof Array
    ? keys
    : Array.prototype.slice.call(arguments);

  if (!keys.length) throw new Error('keys required');

  var actual = Object.keys(this.obj)
    , len = keys.length;

  // Inclusion
  ok = keys.every(function(key){
    return ~actual.indexOf(key);
  });

  // Strict
  if (!this.negate && !this.contains) {
    ok = ok && keys.length == actual.length;
  }

  // Key string
  if (len > 1) {
    keys = keys.map(function(key){
      return inspect(key);
    });
    var last = keys.pop();
    str = keys.join(', ') + ', and ' + last;
  } else {
    str = inspect(keys[0]);
  }

  // Form
  str = (len > 1 ? 'keys ' : 'key ') + str;

  // Have / include
  str = (this.contains ? 'contain ' : 'have ') + str;

  // Assertion
  this.assert(
      ok
    , 'expected ' + this.inspect + ' to ' + str
    , 'expected ' + this.inspect + ' to not ' + str
    , keys
    , Object.keys(this.obj)
  );

  return this;
}
            

.throw(constructor)

Assertion.prototype.throw()

@aliasthrows
@aliasThrow
@param{ ErrorConstructor }constructor
@see
@apipublic

Assert that a function will throw a specific type of error or that error
thrown will match a RegExp or include a string.

 var fn = function () { throw new ReferenceError('This is a bad function.'); }
 expect(fn).to.throw(ReferenceError);
 expect(fn).to.throw(/bad function/);
 expect(fn).to.not.throw('good function');
 expect(fn).to.throw(ReferenceError, /bad function/);

Please note that when a throw expectation is negated, it will check each
parameter independently, starting with Error constructor type. The appropriate way
to check for the existence of a type of error but for a message that does not match
is to use and.

 expect(fn).to.throw(ReferenceError).and.not.throw(/good function/);
View Source
Assertion.prototype.throw = function (constructor, msg) {
  new Assertion(this.obj).is.a('function');

  var thrown = false;

  if (arguments.length === 0) {
    msg = null;
    constructor = null;
  } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
    msg = constructor;
    constructor = null;
  }

  try {
    this.obj();
  } catch (err) {
    // first, check constructor
    if (constructor && 'function' === typeof constructor) {
      this.assert(
          err instanceof constructor && err.name == constructor.name
        , 'expected ' + this.inspect + ' to throw ' + constructor.name + ' but a ' + err.name + ' was thrown'
        , 'expected ' + this.inspect + ' to not throw ' + constructor.name );
      if (!msg) return this;
    }
    // next, check message
    if (err.message && msg && msg instanceof RegExp) {
      this.assert(
          msg.exec(err.message)
        , 'expected ' + this.inspect + ' to throw error matching ' + msg + ' but got ' + inspect(err.message)
        , 'expected ' + this.inspect + ' to throw error not matching ' + msg
      );
      return this;
    } else if (err.message && msg && 'string' === typeof msg) {
      this.assert(
          ~err.message.indexOf(msg)
        , 'expected ' + this.inspect + ' to throw error including ' + inspect(msg) + ' but got ' + inspect(err.message)
        , 'expected ' + this.inspect + ' to throw error not including ' + inspect(msg)
      );
      return this;
    } else {
      thrown = true;
    }
  }

  var name = (constructor ? constructor.name : 'an error');

  this.assert(
      thrown === true
    , 'expected ' + this.inspect + ' to throw ' + name
    , 'expected ' + this.inspect + ' to not throw ' + name);

  return this;
};
            

.respondTo(method)

Assertion.prototype.respondTo()

@param{ String }method
@apipublic

Assert that object/class will respond to a method.

 expect(Klass).to.respondTo('bar');
 expect(obj).to.respondTo('bar');
View Source
Assertion.prototype.respondTo = function (method) {
  var context = ('function' === typeof this.obj)
    ? this.obj.prototype[method]
    : this.obj[method];

  this.assert(
      'function' === typeof context
    , 'expected ' + this.inspect + ' to respond to ' + inspect(method)
    , 'expected ' + this.inspect + ' to not respond to ' + inspect(method)
    , 'function'
    , typeof context
  );

  return this;
};
            

.satisfy(method)

Assertion.prototype.satisfy()

@param{ Function }matcher
@apipublic

Assert that passes a truth test.

 expect(1).to.satisfy(function(num) { return num > 0; });
View Source
Assertion.prototype.satisfy = function (matcher) {
  this.assert(
      matcher(this.obj)
    , 'expected ' + this.inspect + ' to satisfy ' + inspect(matcher)
    , 'expected ' + this.inspect + ' to not satisfy' + inspect(matcher)
    , this.negate ? false : true
    , matcher(this.obj)
  );

  return this;
};
            

.closeTo(expected, delta)

Assertion.prototype.closeTo()

@param{ Number }expected
@param{ Number }delta
@apipublic

Assert that actual is equal to +/- delta.

 expect(1.5).to.be.closeTo(1, 0.5);
View Source
Assertion.prototype.closeTo = function (expected, delta) {
  this.assert(
      (this.obj - delta === expected) || (this.obj + delta === expected)
    , 'expected ' + this.inspect + ' to be close to ' + expected + ' +/- ' + delta
    , 'expected ' + this.inspect + ' not to be close to ' + expected + ' +/- ' + delta);

  return this;
};