Skip to content

Instantly share code, notes, and snippets.

@bynaki
Last active October 8, 2017 16:58
Show Gist options
  • Save bynaki/960ad6c59b481b622736 to your computer and use it in GitHub Desktop.
Save bynaki/960ad6c59b481b622736 to your computer and use it in GitHub Desktop.
Chai - Installation - Node.js - Browser - Assertion Styles -

:origin:

Chai

Installation

Chai is available for both node.js and the browser using any test framework you like. There are also a number of other tools that include Chai.

Node.js

Package is available through npm:

npm install chai

Recommend adding it to package.json devDependencies using a * as the version tag. This will ensure that you always have the most recent version after running npm install, which can be especially powerful when paired with a continuous integration tool.

"devDependencies": {
  "chai": "*",
  "mocha": "*"
}, "//": "mocha is our preference, but you can use any test runner you like"

Browser

Include the chai browser build in your testing suite.

<script src="chai.js" type="text/javascript"></script>

This will provide chai as a global object, or define it if you are using AMD.

The latest tagged version will be available for hot-linking at http://chaijs.com/chai.js. If you prefer to host yourself, use the chai.js file from the root of the github project. We recommend that you always use a version tag as your starting point, so the tag download list is the best place to start.

Currently supports all modern browsers: IE 9+, Chrome 7+, FireFox 4+, Safari 5+. Please note that the should style is currently not compatible with IE9.

If you want to know if your browser is compatible, run the online test suite.

Assertion Styles

This section of the guide introduces you to the three different assertion styles that you may use in your testing environment. Once you have made your selection, it is recommended that you look at the API Documentation for your selected style.

Assert

View full Assert API

The assert style is exposed through assert interface. This provides the classic assert-dot notation, similiar to that packaged with node.js. This assert module, however, provides several additional tests and is browser compatible.

var assert = require('chai').assert
  , foo = 'bar'
  , beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };

assert.typeOf(foo, 'string'); // without optional message
assert.typeOf(foo, 'string', 'foo is a string'); // with optional message
assert.equal(foo, 'bar', 'foo equal `bar`');
assert.lengthOf(foo, 3, 'foo`s value has a length of 3');
assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');

In all cases, the assert style allows you to include an optional message as the last parameter in the assert statement. These will be included in the error messages should your assertion not pass.

BDD

View full BDD API

The BDD style comes in two flavors: expect and should. Both use the same chainable language to construct assertions, but they differ in the way an assertion is initially constructed. In the case of should, there are also some caveats and additional tools to overcome the caveats.

Expect

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

var expect = require('chai').expect
  , foo = 'bar'
  , beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };

expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(beverages).to.have.property('tea').with.length(3);

Expect also allows you to include arbitrary messages to prepend to any failed assertions that might occur.

var answer = 43;

// AssertionError: expected 43 to equal 42.
expect(answer).to.equal(42);

// AssertionError: topic [answer]: expected 43 to equal 42.
expect(answer, 'topic [answer]').to.equal(42);

This comes in handy when being used with non-descript topics such as booleans or numbers.

Should

The should style allows for the same chainable assertions as the expect interface, however it extends each object with a should property to start your chain. This style has some issues when used Internet Explorer, so be aware of browser compatibility.

var should = require('chai').should() //actually call the function
  , foo = 'bar'
  , beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };

foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
beverages.should.have.property('tea').with.length(3);
Differences

First of all, notice that the expect require is just a reference to the expect function, whereas with the should require, the function is being executed.

var chai = require('chai')
  , expect = chai.expect
  , should = chai.should();

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 modern browsers except Internet Explorer.

Should Extras

Given that should works by extending Object.prototype, there are some scenarios where should will not work. Mainly, if you are trying to check the existence of an object. Take the following pseudocode:

db.get(1234, function (err, doc) {
  // we expect error to not exist
  // we expect doc to exist and be an object
});

Given that err should be null or undefined, err.should.not.exist is not a valid statement as undefined and null haven't been extended with a should chain starter. As such, the appropriate few assertions for this scenario are as follows:

var should = require('chai').should();
db.get(1234, function (err, doc) {
  should.not.exist(err);
  should.exist(doc);
  doc.should.be.an('object');
});

Provided you assigned should to a var, you have access to several quick helpers to keep you out of trouble when using should.

  • should.exist
  • should.not.exist
  • should.equal
  • should.not.equal
  • should.Throw
  • should.not.Throw

Configuration

config.includeStack
  • @param {Boolean}
  • @default false

User configurable property, influences whether stack trace is included in Assertion error message. Default of false suppresses stack trace in the error message.

chai.config.includeStack = true; // turn on stack trace
config.showDiff
  • @param {Boolean}
  • @default true

User configurable property, influences whether or not the showDiff flag should be included in the thrown AssertionErrors. false will always be false; true will be true when the assertion has requested a diff be shown.

chai.config.showDiff = false; // turn off reporter diff display
config.truncateThreshold
  • @param {Number}
  • @default 40

User configurable property, sets length threshold for actual and expected values in assertion errors. If this threshold is exceeded, the value is truncated.

Set it to zero if you want to disable truncating altogether.

chai.config.truncateThreshold = 0; // disable truncating

BDD

The BDD styles are expect and should. Both use the same chainable language to construct assertions, but they differ in the way an assertion is initially constructed. Check out the Style Guide for a comparison.

API Reference

Language Chains

The following are provided as chainable getters to improve the readability of your assertions. They do not provide testing capabilities unless they have been overwritten by a plugin.

Chains
  • to
  • be
  • been
  • is
  • that
  • which
  • and
  • has
  • have
  • with
  • at
  • of
  • same
.not

Negates any of assertions following in the chain.

expect(foo).to.not.equal('bar');
expect(goodFn).to.not.throw(Error);
expect({ foo: 'baz' }).to.have.property('foo')
  .and.not.equal('bar');
.deep

Sets the deep flag, later used by the equal and property assertions.

expect(foo).to.deep.equal({ bar: 'baz' });
expect({ foo: { bar: { baz: 'quux' } } })
  .to.have.deep.property('foo.bar.baz', 'quux');
.any

Sets the any flag, (opposite of the all flag) later used in the keys assertion.

expect(foo).to.have.any.keys('bar', 'baz');
.all

Sets the all flag (opposite of the any flag) later used by the keys assertion.

expect(foo).to.have.all.keys('bar', 'baz');
.a(type)
  • @param{ String }type
  • @param{ String }message_optional_

The a and an assertions are aliases that can be used either as language chains or to assert a value's type.

// typeof
expect('test').to.be.a('string');
expect({ foo: 'bar' }).to.be.an('object');
expect(null).to.be.a('null');
expect(undefined).to.be.an('undefined');

// language chain
expect(foo).to.be.an.instanceof(Foo);
.include(value)
  • @param{ Object | String | Number }obj
  • @param{ String }message_optional_

The include and contain assertions can be used as either property based language chains or as methods to assert the inclusion of an object in an array or a substring in a string. When used as language chains, they toggle the contains flag for the keys assertion.

expect([1,2,3]).to.include(2);
expect('foobar').to.contain('foo');
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
.ok

Asserts that the target is truthy.

expect('everthing').to.be.ok;
expect(1).to.be.ok;
expect(false).to.not.be.ok;
expect(undefined).to.not.be.ok;
expect(null).to.not.be.ok;
.true

Asserts that the target is true.

expect(true).to.be.true;
expect(1).to.not.be.true;
.false

Asserts that the target is false.

expect(false).to.be.false;
expect(0).to.not.be.false;
.null

Asserts that the target is null.

expect(null).to.be.null;
expect(undefined).not.to.be.null;
.undefined

Asserts that the target is undefined.

expect(undefined).to.be.undefined;
expect(null).to.not.be.undefined;
.exist

Asserts that the target is neither null nor undefined.

var foo = 'hi'
  , bar = null
  , baz;

expect(foo).to.exist;
expect(bar).to.not.exist;
expect(baz).to.not.exist;
.empty

Asserts that the target's length is 0. For arrays, it checks the length property. For objects, it gets the count of enumerable keys.

expect([]).to.be.empty;
expect('').to.be.empty;
expect({}).to.be.empty;
.arguments

Asserts that the target is an arguments object.

function test () {
  expect(arguments).to.be.arguments;
}
.equal(value)
  • @param{ Mixed }value
  • @param{ String }message_optional_

Asserts that the target is strictly equal (===) to value. Alternately, if the deep flag is set, asserts that the target is deeply equal to value.

expect('hello').to.equal('hello');
expect(42).to.equal(42);
expect(1).to.not.equal(true);
expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
.eql(value)
  • @param{ Mixed }value
  • @param{ String }message_optional_

Asserts that the target is deeply equal to value.

expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
.above(value)
  • @param{ Number }value
  • @param{ String }message_optional_

Asserts that the target is greater than value.

expect(10).to.be.above(5);

Can also be used in conjunction with length to assert a minimum length. The benefit being a more informative error message than if the length was supplied directly.

expect('foo').to.have.length.above(2);
expect([ 1, 2, 3 ]).to.have.length.above(2);
.least(value)
  • @param{ Number }value
  • @param{ String }message_optional_

Asserts that the target is greater than or equal to value.

expect(10).to.be.at.least(10);

Can also be used in conjunction with length to assert a minimum length. The benefit being a more informative error message than if the length was supplied directly.

expect('foo').to.have.length.of.at.least(2);
expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
.below(value)
  • @param{ Number }value
  • @param{ String }message_optional_

Asserts that the target is less than value.

expect(5).to.be.below(10);

Can also be used in conjunction with length to assert a maximum length. The benefit being a more informative error message than if the length was supplied directly.

expect('foo').to.have.length.below(4);
expect([ 1, 2, 3 ]).to.have.length.below(4);
.most(value)
  • @param{ Number }value
  • @param{ String }message_optional_

Asserts that the target is less than or equal to value.

expect(5).to.be.at.most(5);

Can also be used in conjunction with length to assert a maximum length. The benefit being a more informative error message than if the length was supplied directly.

expect('foo').to.have.length.of.at.most(4);
expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
.within(start, finish)
  • @param{ Number }startlowerbound inclusive
  • @param{ Number }finishupperbound inclusive
  • @param{ String }message_optional_

Asserts that the target is within a range.

expect(7).to.be.within(5,10);

Can also be used in conjunction with length to assert a length range. The benefit being a more informative error message than if the length was supplied directly.

expect('foo').to.have.length.within(2,4);
expect([ 1, 2, 3 ]).to.have.length.within(2,4);
.instanceof(constructor)
  • @param{ Constructor }constructor
  • @param{ String }message_optional_

Asserts that the target is an instance of constructor.

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

expect(Chai).to.be.an.instanceof(Tea);
expect([ 1, 2, 3 ]).to.be.instanceof(Array);
.property(name, [value])
  • @param{ String }name
  • @param{ Mixed }value(optional)
  • @param{ String }message_optional_

Asserts that the target has a property name, optionally asserting that the value of that property is strictly equal to value. If the deep flag is set, you can use dot- and bracket-notation for deep references into objects and arrays.

// simple referencing
var obj = { foo: 'bar' };
expect(obj).to.have.property('foo');
expect(obj).to.have.property('foo', 'bar');

// deep referencing
var deepObj = {
    green: { tea: 'matcha' }
  , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
};

expect(deepObj).to.have.deep.property('green.tea', 'matcha');
expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');

You can also use an array as the starting point of a deep.property assertion, or traverse nested arrays.

var arr = [
    [ 'chai', 'matcha', 'konacha' ]
  , [ { tea: 'chai' }
    , { tea: 'matcha' }
    , { tea: 'konacha' } ]
];

expect(arr).to.have.deep.property('[0][1]', 'matcha');
expect(arr).to.have.deep.property('[1][2].tea', 'konacha');

Furthermore, property changes the subject of the assertion to be the value of that property from the original object. This permits for further chainable assertions on that property.

expect(obj).to.have.property('foo')
  .that.is.a('string');
expect(deepObj).to.have.property('green')
  .that.is.an('object')
  .that.deep.equals({ tea: 'matcha' });
expect(deepObj).to.have.property('teas')
  .that.is.an('array')
  .with.deep.property('[2]')
    .that.deep.equals({ tea: 'konacha' });
.ownProperty(name)
  • @param{ String }name
  • @param{ String }message_optional_

Asserts that the target has an own property name.

expect('test').to.have.ownProperty('length');
.length(value)
  • @param{ Number }length
  • @param{ String }message_optional_

Asserts that the target's length property has the expected value.

expect([ 1, 2, 3]).to.have.length(3);
expect('foobar').to.have.length(6);

Can also be used as a chain precursor to a value comparison for the length property.

expect('foo').to.have.length.above(2);
expect([ 1, 2, 3 ]).to.have.length.above(2);
expect('foo').to.have.length.below(4);
expect([ 1, 2, 3 ]).to.have.length.below(4);
expect('foo').to.have.length.within(2,4);
expect([ 1, 2, 3 ]).to.have.length.within(2,4);
.match(regexp)
  • @param{ RegExp }RegularExpression
  • @param{ String }message_optional_

Asserts that the target matches a regular expression.

expect('foobar').to.match(/^foo/);
.string(string)
  • @param{ String }string
  • @param{ String }message_optional_

Asserts that the string target contains another string.

expect('foobar').to.have.string('bar');
.keys(key1, [key2], [...])
  • @param{ String... | Array | Object }keys

Asserts that the target contains any or all of the passed-in keys. Use in combination with any, all, contains, or have will affect what will pass.

When used in conjunction with any, at least one key that is passed in must exist in the target object. This is regardless whether or not the have or contain qualifiers are used. Note, either any or all should be used in the assertion. If neither are used, the assertion is defaulted to all.

When both all and contain are used, the target object must have at least all of the passed-in keys but may have more keys not listed.

When both all and have are used, the target object must both contain all of the passed-in keys AND the number of keys in the target object must match the number of keys passed in (in other words, a target object must have all and only all of the passed-in keys).

expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz');
expect({ foo: 1, bar: 2 }).to.have.any.keys('foo');
expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz');
expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']);
expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6});
expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']);
expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo', 7});
expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']);
expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys([{'bar': 6}}]);
.throw(constructor)

Asserts that the function target will throw a specific error, or specific type of error (as determined using instanceof), optionally with a RegExp or string inclusion test for the error's message.

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

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/);
.respondTo(method)
  • @param{ String }method
  • @param{ String }message_optional_

Asserts that the object or class target will respond to a method.

Klass.prototype.bar = function(){};
expect(Klass).to.respondTo('bar');
expect(obj).to.respondTo('bar');

To check if a constructor will respond to a static function, set the itself flag.

Klass.baz = function(){};
expect(Klass).itself.to.respondTo('baz');
.itself

Sets the itself flag, later used by the respondTo assertion.

function Foo() {}
Foo.bar = function() {}
Foo.prototype.baz = function() {}

expect(Foo).itself.to.respondTo('bar');
expect(Foo).itself.not.to.respondTo('baz');
.satisfy(method)
  • @param{ Function }matcher
  • @param{ String }message_optional_

Asserts that the target passes a given truth test.

expect(1).to.satisfy(function(num) { return num > 0; });
.closeTo(expected, delta)
  • @param{ Number }expected
  • @param{ Number }delta
  • @param{ String }message_optional_

Asserts that the target is equal expected, to within a +/- delta range.

expect(1.5).to.be.closeTo(1, 0.5);
.members(set)
  • @param{ Array }set
  • @param{ String }message_optional_

Asserts that the target is a superset of set, or that the target and set have the same strictly-equal (===) members. Alternately, if the deep flag is set, set members are compared for deep equality.

expect([1, 2, 3]).to.include.members([3, 2]);
expect([1, 2, 3]).to.not.include.members([3, 2, 8]);

expect([4, 2]).to.have.members([2, 4]);
expect([5, 2]).to.not.have.members([5, 2, 1]);

expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]);
.change(function)
  • @param{ String }object
  • @param{ String }propertyname
  • @param{ String }message_optional_

Asserts that a function changes an object property

var obj = { val: 10 };
var fn = function() { obj.val += 3 };
var noChangeFn = function() { return 'foo' + 'bar'; }
expect(fn).to.change(obj, 'val');
expect(noChangFn).to.not.change(obj, 'val')
.increase(function)
  • @param{ String }object
  • @param{ String }propertyname
  • @param{ String }message_optional_

Asserts that a function increases an object property

var obj = { val: 10 };
var fn = function() { obj.val = 15 };
expect(fn).to.increase(obj, 'val');
.decrease(function)
  • @param{ String }object
  • @param{ String }propertyname
  • @param{ String }message_optional_

Asserts that a function decreases an object property

var obj = { val: 10 };
var fn = function() { obj.val = 5 };
expect(fn).to.decrease(obj, 'val');

Chai Assertions for Promises

Chai as Promised extends Chai with a fluent language for asserting facts about promises.

Instead of manually wiring up your expectations to a promise's fulfilled and rejected handlers:

doSomethingAsync().then(
    function (result) {
        result.should.equal("foo");
        done();
    },
    function (err) {
       done(err);
    }
);

you can write code that expresses what you really mean:

return doSomethingAsync().should.eventually.equal("foo");

or if you have a case where return is not preferable (e.g. style considerations) or not possible (e.g. the testing framework doesn't allow returning promises to signal asynchronous test completion), then you can use the following workaround (where done() is supplied by the test framework):

doSomethingAsync().should.eventually.equal("foo").notify(done);

Notice: either return or notify(done) must be used with promise assertions. This can be a slight departure from the existing format of assertions being used on a project or by a team. Those other assertions are likely synchronous and thus do not require special handling.

How to Use

should/expect Interface

The most powerful extension provided by Chai as Promised is the eventually property. With it, you can transform any existing Chai assertion into one that acts on a promise:

(2 + 2).should.equal(4);

// becomes
return Promise.resolve(2 + 2).should.eventually.equal(4);


expect({ foo: "bar" }).to.have.property("foo");

// becomes
return expect(Promise.resolve({ foo: "bar" })).to.eventually.have.property("foo");

There are also a few promise-specific extensions (with the usual expect equivalents also available):

return promise.should.be.fulfilled;
return promise.should.eventually.deep.equal("foo");
return promise.should.become("foo"); // same as `.eventually.deep.equal`
return promise.should.be.rejected;
return promise.should.be.rejectedWith(Error); // other variants of Chai's `throw` assertion work too.

assert Interface

As with the should/expect interface, Chai as Promised provides an eventually extender to chai.assert, allowing any existing Chai assertion to be used on a promise:

assert.equal(2 + 2, 4, "This had better be true");

// becomes
return assert.eventually.equal(Promise.resolve(2 + 2), 4, "This had better be true, eventually");

And there are, of course, promise-specific extensions:

return assert.isFulfilled(promise, "optional message");

return assert.becomes(promise, "foo", "optional message");
return assert.doesNotBecome(promise, "foo", "optional message");

return assert.isRejected(promise, "optional message");
return assert.isRejected(promise, Error, "optional message");
return assert.isRejected(promise, /error message matcher/, "optional message");

Progress Callbacks

Chai as Promised does not have any intrinsic support for testing promise progress callbacks. The properties you would want to test are probably much better suited to a library like Sinon.JS, perhaps in conjunction with Sinon–Chai:

var progressSpy = sinon.spy();

return promise.then(null, null, progressSpy).then(function () {
    progressSpy.should.have.been.calledWith("33%");
    progressSpy.should.have.been.calledWith("67%");
    progressSpy.should.have.been.calledThrice;
});

Customizing Output Promises

By default, the promises returned by Chai as Promised's assertions are regular Chai assertion objects, extended with a single then method derived from the input promise. To change this behavior, for instance to output a promise with more useful sugar methods such as are found in most promise libraries, you can override chaiAsPromised.transferPromiseness. Here's an example that transfer's Q's finally and done methods:

chaiAsPromised.transferPromiseness = function (assertion, promise) {
    assertion.then = promise.then.bind(promise); // this is all you get by default
    assertion.finally = promise.finally.bind(promise);
    assertion.done = promise.done.bind(promise);
};

Transforming Arguments to the Asserters

Another advanced customization hook Chai as Promised allows is if you want to transform the arguments to the asserters, possibly asynchronously. Here is a toy example:

chaiAsPromised.transformAsserterArgs = function (args) {
    return args.map(function (x) { return x + 1; });
}

Promise.resolve(2).should.eventually.equal(2); // will now fail!
Promise.resolve(2).should.eventually.equal(3); // will now pass!

The transform can even be asynchronous, returning a promise for an array instead of an array directly. An example of that might be using Promise.all so that an array of promises becomes a promise for an array. If you do that, then you can compare promises against other promises using the asserters:

// This will normally fail, since within() only works on numbers.
Promise.resolve(2).should.eventually.be.within(Promise.resolve(1), Promise.resolve(6));

chaiAsPromised.transformAsserterArgs = function (args) {
    return Promise.all(args);
};

// But now it will pass, since we transformed the array of promises for numbers into
// (a promise for) an array of numbers
Promise.resolve(2).should.eventually.be.within(Promise.resolve(1), Promise.resolve(6));

Compatibility

Chai as Promised is compatible with all promises following the Promises/A+ specification. Notably, jQuery's so-called “promises” are not up to spec, and Chai as Promised will not work with them. In particular, Chai as Promised makes extensive use of the standard transformation behavior of then, which jQuery does not support.

Working with Non-Promise–Friendly Test Runners

Some test runners (e.g. Jasmine, QUnit, or tap/tape) do not have the ability to use the returned promise to signal asynchronous test completion. If possible, I'd recommend switching to ones that do, such as Mocha, Buster, or blue-tape. But if that's not an option, Chai as Promised still has you covered. As long as your test framework takes a callback indicating when the asynchronous test run is over, Chai as Promised can adapt to that situation with its notify method, like so:

it("should be fulfilled", function (done) {
    promise.should.be.fulfilled.and.notify(done);
});

it("should be rejected", function (done) {
    otherPromise.should.be.rejected.and.notify(done);
});

In these examples, if the conditions are not met, the test runner will receive an error of the form "expected promise to be fulfilled but it was rejected with [Error: error message]", or "expected promise to be rejected but it was fulfilled."

There's another form of notify which is useful in certain situations, like doing assertions after a promise is complete. For example:

it("should change the state", function (done) {
    otherState.should.equal("before");
    promise.should.be.fulfilled.then(function () {
        otherState.should.equal("after");
    }).should.notify(done);
});

Notice how .notify(done) is hanging directly off of .should, instead of appearing after a promise assertion. This indicates to Chai as Promised that it should pass fulfillment or rejection directly through to the testing framework. Thus, the above code will fail with a Chai as Promised error ("expected promise to be fulfilled…") if promise is rejected, but will fail with a simple Chai error (expected "before" to equal "after") if otherState does not change.

Multiple Promise Assertions

To perform assertions on multiple promises, use Promise.all to combine multiple Chai as Promised assertions:

it("should all be well", function () {
    return Promise.all([
        promiseA.should.become("happy"),
        promiseB.should.eventually.have.property("fun times"),
        promiseC.should.be.rejectedWith(TypeError, "only joyful types are allowed")
    ]);
});

This will pass any failures of the individual promise assertions up to the test framework, instead of wrapping them in an "expected promise to be fulfilled…" message as would happen if you did return Promise.all([…]).should.be.fulfilled. If you can't use return, then use .should.notify(done), similar to the previous examples.

Installation and Setup

Node

Do an npm install chai-as-promised to get up and running. Then:

var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");

chai.use(chaiAsPromised);

You can of course put this code in a common test fixture file; for an example using Mocha, see the Chai as Promised tests themselves.

AMD

Chai as Promised supports being used as an AMD module, registering itself anonymously (just like Chai). So, assuming you have configured your loader to map the Chai and Chai as Promised files to the respective module IDs "chai" and "chai-as-promised", you can use them as follows:

define(function (require, exports, module) {
    var chai = require("chai");
    var chaiAsPromised = require("chai-as-promised");

    chai.use(chaiAsPromised);
});

<script> tag

If you include Chai as Promised directly with a <script> tag, after the one for Chai itself, then it will automatically plug in to Chai and be ready for use:

<script src="chai.js"></script>
<script src="chai-as-promised.js"></script>

Karma

If you're using Karma, check out the accompanying karma-chai-as-promised plugin.

Browser Compatibility

Chai as Promised is only compatible with modern browsers (IE ≥9, Safari ≥6, no PhantomJS).

{"noteId":"15162a5ecc4-f31f2321","main":"15162a5ecc4-f31f2321.md","title":"Chai - Installation - Node.js - Browser - Assertion Styles - Assert - BDD - Expect - Should - Differences - Should Extras - Configuration - config.includeStack - config.showDiff - config.truncateThreshold - BDD - API Reference - Language Chains - Chains - .not - .deep - .any - .all - .a(type) - .include(value) - .ok - .true - .false - .null - .undefined - .exist - .empty - .arguments - .equal(value) - .eql(value) - .above(value) - .least(value) - .below(value) - .most(value) - .within(start, finish) - .instanceof(constructor) - .property(name, [value]) - .ownProperty(name) - .length(value) - .match(regexp) - .string(string) - .keys(key1, [key2], [...]) - .throw(constructor) - .respondTo(method) - .itself - .satisfy(method) - .closeTo(expected, delta) - .members(set) - .change(function) - .increase(function) - .decrease(function) - Chai Assertions for Promises - How to Use - <code>should</code>/<code>expect</code> Interface - <code>assert</code> Interface - Progress Callbacks - Customizing Output Promises - Transforming Arguments to the Asserters - Compatibility - Working with Non-Promise–Friendly Test Runners - Multiple Promise Assertions - Installation and Setup - Node - AMD - <code>&lt;script&gt;</code> tag - Karma - Browser Compatibility"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment