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.
View Source
Object.defineProperty(Assertion.prototype, 'to',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'be',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'an',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'is',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'and',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'have',
{ get: function () {
return this;
}
});
View Source
Object.defineProperty(Assertion.prototype, 'with',
{ get: function () {
return this;
}
});
Negates any of assertions following in the chain.
View Source
Object.defineProperty(Assertion.prototype, 'not',
{ get: function () {
this.negate = true;
return this;
}
});
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;
}
});
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;
}
});
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;
}
});
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;
}
});
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;
}
});
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;
}
});
Assertion.prototype.equal()
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;
};
Assertion.prototype.eql()
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;
};
Assertion.prototype.above()
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;
};
Assertion.prototype.below()
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;
};
Assertion.prototype.within()
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;
};
Assertion.prototype.a()
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;
};
Assertion.prototype.instanceof()
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;
};
Assertion.prototype.property()
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;
};
Assertion.prototype.ownProperty()
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;
};
Assertion.prototype.length()
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;
};
Assertion.prototype.match()
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;
};
Assertion.prototype.include()
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;
};
Assertion.prototype.string()
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;
};
Toggles the contain
flag for the keys
assertion.
View Source
Object.defineProperty(Assertion.prototype, 'contain',
{ get: function () {
this.contains = true;
return this;
}
});
Assertion.prototype.keys()
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;
}
Assertion.prototype.throw()
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;
};
Assertion.prototype.status()
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]));
}
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;
}
});
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;
}
});