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...
Fork me on GitHub
git clone https://github.com/logicalparadox/chai.git

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 both node.js and in the browser.

The should interface extends Object.prototype to provide a single getter as
the starting point for your language assertions. Most browser don't like
extensions to Object.prototype so it is not recommended for browser use.

to

@apipublic

Language chain.

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

be

@apipublic

Language chain.

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

an

@apipublic

Language chain.

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

is

@apipublic

Language chain.

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

and

@apipublic

Language chain.

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

have

@apipublic

Language chain.

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

with

@apipublic

Language chain.

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

.not

@apipublic

Negates any of assertions following in the chain.

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

.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 falsey');

      return this;
    }
});
            

.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');

      return this;
    }
});
            

.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');

      return this;
    }
});
            

.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;
    }
});
            

.empty

@apipublic

Assert object's length to be 0.

 expect([]).to.be.empty;
View Source
Object.defineProperty(Assertion.prototype, 'empty',
  { get: function () {
      new Assertion(this.obj).to.have.property('length');

      this.assert(
          0 === this.obj.length
        , 'expected ' + this.inspect + ' to be empty'
        , 'expected ' + this.inspect + ' not to be empty');

      return this;
    }
});
            

.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');

      return this;
    }
});
            

.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));

  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));
  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) {
  this.assert(
      type == typeof this.obj
    , 'expected ' + this.inspect + ' to be a ' + type
    , 'expected ' + this.inspect + ' not to be a ' + type);

  return this;
};
            

.instanceOf(constructor)

Assertion.prototype.instanceof()

@param{ Constructor }
@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));
  }

  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);

  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.contain(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.include.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;
    }
});
            

.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);

  return this;
}
            

.throw(constructor)

Assertion.prototype.throw()

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

Assert that a function will throw a specific type of error.

 var fn = function () { throw new ReferenceError(''); }
 expect(fn).to.throw(ReferenceError);
View Source
Assertion.prototype.throw = function (constructor) {
  new Assertion(this.obj).is.a('function');

  var thrown = false;

  try {
    this.obj();
  } catch (err) {
    if (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 );

      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;
};
            

.header(code)

Assertion.prototype.header()

@param{ String }field
@param{ String }value
@apipublic

Assert header field has expected value.

View Source
Assertion.prototype.header = function (field, val) {
  new Assertion(this.obj)
        .to.have.property('headers').and
        .to.have.property(field.toLowerCase(), val);

  return this;
}
            

.status(code)

Assertion.prototype.status()

@param{ Number }code
@apipublic

Assert statusCode of `code'.

View Source
Assertion.prototype.status = function (code) {
  new Assertion(this.obj).to.have.property('statusCode');

  var status = this.obj.statusCode;

  this.assert(
      code == status
    , 'expected response code of ' + code + ' ' + inspect(statusCodes[code])
        + ', but got ' + status + ' ' + inspect(statusCodes[status])
    , 'expected to not respond with ' + code + ' ' + inspect(statusCodes[code]));
}
            

json

@apipublic

Assert that this response has content-type: application/json.

View Source
Object.defineProperty(Assertion.prototype, 'json',
  { get: function () {
      new Assertion(this.obj).to.have.header('content-type', 'application/json; charset=utf-8');
      return this;
    }
});
            

html

@apipublic

Assert that this response has content-type: text/html.

View Source
Object.defineProperty(Assertion.prototype, 'html',
  { get: function () {
      new Assertion(this.obj).to.have.header('content-type', 'text/html; charset=utf-8');
      return this;
    }
});