Release History


Version 4.0.0-canary.1


Breaking Changes

  • Instead of allowing the user to write the path of a property, now the deep flag performs a deep equality comparison when used with the .property assertion. If you want the old behavior of using the dot or bracket notation to denote the property you want to assert against you can use the new .nested flag. (Related Issues: #745, #743, PRs: #758, #757)

    const obj = {a: 1};
    // The `.deep` flag now does deep equality comparisons
    expect({foo: obj})'foo', {a: 1});
    // Use the `nested` flag if you want to assert against a nested property using the bracket or dot notation
    expect({foo: obj})'foo.a', 1);
    // You can also use both flags combined
    const obj2 = {a: {b: 2}};
    expect({foo: obj2})'foo.a', {b: 2});

    Please notice that the old methods which used the old behavior of the deep flag on the assert interface have been renamed. They all have had the deep word changed by the nested word. If you want to know more about this please take a look at #757.

  • Previously, expect(obj), val) would throw an Error if obj didn’t have a property named name. This change causes the assertion to pass instead. The assert.propertyNotVal and assert.deepPropertyNotVal assertions were renamed to assert.notPropertyVal and assert.notDeepPropertyVal, respectively. (Related Issues: #16, #743, #758)
  • You can now use the deep flag for the .include assertion in order to perform a deep equality check to see if something is included on the target. Previously, .include was using strict equality (===) for non-negated property inclusion, but deep equality for negated property inclusion and array inclusion. This change causes the .include assertion to always use strict equality unless the deep flag is set. Please take a look at this comment if you want to know more about it. (Related Issues: #743, PRs: #760, #761)

    const obj = {a: 1};
    expect({foo: obj}).to.deep.include({foo: {a:1}});
  • Fix unstable behavior of the NaN assertion. Now we use the suggested ES6 implementation. The new implementation is now more correct, strict and simple. While the old one threw false positives, the new implementation only checks if something is NaN (or not if the .not flag is used) and nothing else. (Related Issues: #498, #682, #681, PRs: #508)

    // Only `NaN` will be considered to be `NaN` and nothing else
    // Anything that is not `NaN` cannot be considered as `NaN`
  • Throw when calling _superon overwriteMethodif the method being overwritten is undefined. Currently if the method you are trying to overwrite is not defined and your new method calls _super it will throw an Error.(Related Issues: #467, PRs: #528) Before this change, calling _super would simply return this.

    // Considering the method `imaginaryMethod` does not exist, this would throw an error for example:
    chai.use(function (chai, utilities) {
      chai.Assertion.overwriteMethod('imaginaryMethod', function (_super) {
        return function () {
          _super.apply(this, arguments);
    // This will throw an error since you are calling `_super` which should be a method (in this case, the overwritten assertion) that does not exist
  • Now showDiff is turned on by default whenever the showDiff flag is anything other than false. This issue will mostly affect plugin creators or anyone that made extensions to the core, since this affects the Assertion.assert method. (Related Issues: #574, PRs: #515)

    // Now whenever you call `Assertion.assert` with anything that is not false for the `showDiff` flag it will be true
    // The assertion error that was thrown will have the `showDiff` flag turned on since it was not passed to the `assert` method
    try {
      new chai.Assertion().assert(
          'one' === 'two'
        , 'expected #{this} to equal #{exp}'
        , 'expected #{this} to not equal #{act}'
        , 'one'
        , 'two'
    } catch(e) {
    // The assertion error that was thrown will have the `showDiff` flag turned off since here we passed `false` explicitly
    try {
      new chai.Assertion().assert(
          'one' === 'two'
        , 'expected #{this} to equal #{exp}'
        , 'expected #{this} to not equal #{act}'
        , 'one'
        , 'two'
        , false
    } catch(e) {
  • The Typed Array types are now truncated if they’re too long (in this case, if they exceed the truncateThreshold value on the config). (Related Issues: #441, PRs: #576)

    var arr = [];
    for (var i = 1; i <= 1000; i++) {
    // The assertion below will truncate the diff shown and the enourmous typed array will be shown as:
    // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...  ] instead of printing the whole typed array
    chai.expect(new Float32Array(100)).to.equal(1);
  • The assertions: within, above, least, below, most, increase, decrease will throw an error if the assertion’s target or arguments are not numbers. (Related Issues: #691, PRs: #692, #796)

    // These will throw errors, for example:
    expect(null), 1);
    // This will not:
  • Previously, expect(obj).not.ownProperty(name, val) would throw an Error if obj didn’t have an own property (non-inherited) named name. This change causes the assertion to pass instead. (Related Issues: #795, #, PRs: #744, #810)*

    expect({ foo: 'baz' })'quux', 'baz');
  • The .empty assertion will now throw when it is passed non-string primitives and functions (PRs: #763, #812)

    // These will throw TypeErrors:
    expect(function() {});
  • Assertion subject (obj) changes when using ownProperty or and thus enables chaining. (Related Issues: #281, PRs: #641)

    expect({val: 20})'val').above(10);
  • The utils (second argument passed to the chai.use callback function) no longer exports the getPathValue function. If you want to use that please use the pathval module, which is what chai uses internally now. (Related Issues: #457, #737, PRs: #830)

New Features

  • Throw when non-existent property is read. (Related Issues: #407, #766 PRs: #721, #770) This is a potentially breaking change. Your build will fail if you have typos in your property assertions Before 4.x.x when using property assertions they would not throw an error if you wrote it incorrectly. The example below, for example, would pass:

    expect(true); // Oops, typo, now Chai will throw an Error

    Since this implementation depends on ES6 Proxies it will only work on platforms that support it.

    This property can be enabled (default) or disabled through the config.useProxy property, for example:

    chai.config.useProxy = false;  // disable use of Proxy
  • Add fix suggestions when accessing a nonexistent property in proxy mode. (Related Issues: #771, PRs: #782) When a nonexistent property is accessed in proxy mode, Chai will compute the levenshtein distance to all possible properties in order to suggest the best fix to the user.

    expect(false); // Error: Invalid Chai property: fals. Did you mean "false"?
    expect('foo'); // Error: Invalid Chai property: undefind. Did you mean "undefined"?
    // If the Levenshtein distance between the word and any Chai property is greater than 4, no fix will be suggested
    expect('foo') // error thrown, no fix suggested
  • When non-chainable methods (including overwritten non-chainable methods) are used incorrectly an error will be thrown with a helpful error message. (PRs: #789)

    expect(true).to.equal.true;  // Invalid Chai property: equal.true. See docs for proper usage of "equal".
  • Add a new configuration setting that describes which keys will be ignored when checking for non-existing properties on an assertion before throwing an error. Since this implementation depends on ES6 Proxies it will only work on platforms that support it. Also, if you disable config.useProxy, this setting will have no effect. *(Related Issues: #765, PRs: #774)

    expect('my string').to.nonExistingProp; // This won't throw an error now
  • Add script that registers should as a side-effect. (Related Issues: #594, #693 PRs: #604)

    // You can now write:
    import 'chai/should';
    // as opposed to:
    import {should} from 'chai';

    You can also register should via a mocha option: mocha --require chai/should.

  • The change assertion accepts a function as object. (Related Issues: #544, PRs: #607)

    // Now you can also check if the return value of a function changes, for example
      () => getSomething().length
  • You can also assert for a delta using the by assertion alongside the change, increase and decrease assertions. (Related Issues: #339, PRs: #621)

  // You can use `.by` to assert the amount you want something to change
  var obj = { val: 10 };
  var increaseByTwo = function() { obj.val += 2 };
  var decreaseByTwo = function() { obj.val -= 2 };
  var increaseByThree = function() { obj.val += 3 };
  expect(increaseByThree).to.change(obj, 'val').by(3);
  expect(increaseByTwo).to.increase(obj, 'val').by(2);
  expect(decreaseByTwo).to.decrease(obj, 'val').by(2);
  // Please notice that if you want to assert something did change but not by some amount you need to use `.not` **after** the `change` related assertion
  // Take a look at the examples below:
  expect(increaseByThree).to.change(obj, 'val')
  expect(increaseByTwo).to.increase(obj, 'val')
  expect(decreaseByTwo).to.decrease(obj, 'val')
  • The .keys assertion can now operate on maps and sets. (Related Issues: #632, PRs: #633, #668)
  // The `.keys` assertion now works on `map`s and `set`s natively, like the examples below:
  expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.key({objKey: 'value'});
  expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.any.keys([{objKey: 'value'}, {anotherKey: 'anotherValue'}]);
  expect(new Map([['firstKey', 'firstValue'], [1, 2]])).to.contain.all.keys('firstKey', 1);
  expect(new Set([['foo', 'bar'], ['example', 1]])).to.have.any.keys('foo');
  // You can also use `.deep` when asserting agains `Map`s and `Set`s
  expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.any.deep.keys([{objKey: 'value'}, {anotherKey: 'anotherValue'}]);
  expect(new Map([['firstKey', 'firstValue'], [1, 2]])).to.contain.all.deep.keys('firstKey', 1);
  expect(new Set([['foo', 'bar'], ['example', 1]])).to.have.any.deep.keys('foo');
  • Add compatibility with strict mode. (Related Issues: #578, PRs: #665)

    // This means you can now run your code with the `--use_strict` flag on Node
    // If want to understand more about this please read the issue related to this change
  • Add does and but as new no-op assertion. (Related Issues: #700, #339 PRs: #621, #701)

    // You can now write assertions forming phrases with these two new words:
    expect(increaseByThree).to.change(obj, 'val');
  • Allow use to be imported using new ES6 module syntax. (Related Issues: #718, PRs: #724)

    // You can now import `use` using the ES6 module syntax, like the example below:
    import sinonChai from "sinon-chai";
    import {expect, use} from "chai";

    You can also use require alongside the new ES6 destructuring feature:

    const sinonChai = require('sinon-chai');
    const {expect, use} = require("chai");
  • Add ordered flag for members assertion. (Related Issues: #717, PRs: #728)

    // You can now use the `ordered` flag to assert the order of elements when using the `members` assertion:
    expect([1, 2, 3]).to.include.ordered.members([1, 2]); // This passes
    expect([1, 2, 3]).to.include.ordered.members([2, 3]); // This will fail! Read the docs to know more.
  • Add .own flag to .property assertion. It does the same thing as .ownProperty and cannot be used alongisde the new .nested flag. (Related Issues: #795, PRs: #810)

    expect({a: 1})'a');
    // The example below will thrown an Error
    expect({a: {b: 1}})'a.b', 1);
  • Add .deep support to .property assertion. (Related Issues: #795, PRs: #810)

    expect({ foo: { bar: 'baz' } })'foo', { bar: 'baz' });
    expect({ foo: { bar: { baz: 'quux' } } })'', { baz: 'quux' });
  • The .empty assertion will now work with ES6 collections (PRs: #763, #812, #814) Please notice that this assertion will throw an error when it is passed a WeakMap or WeakSet.

    expect(new Set());
    expect(new Map());
    // The examples below will throw a TypeError:
    expect(new WeakSet());
    expect(new WeakMap());

Bug Fixes

  • Fix missing msg argument for change related assertions. (Related Issues: None, PRs: #606)
  • The addMethod function returns a new assertion with flags copied over instead of this. (Related Issues: #562, #684, #723, PRs: #642, #660)
  • Fix stacktraces for overwritten properties and methods. (Related Issues: #659, #661)
  • Fix bug when testing Symbol equality with should syntax. (Related Issues: #669, PRs: #672)
  • Fix bug when asserting some valid ES6 keys. (Related Issues: #674, PRs: #676)
  • Fix bug caused when custom inspect method is used and this method calls stylize. (PRs: #680)
  • Fix ownProperty on objects with no prototype. (Related Issues: #688, PRs: #689)
  • Fix swapped expected and actual results for the .members assertion. (Related Issues: #511, PRs: #702)
  • Fix same.members to properly handle duplicates by treating each one as a unique member. (Related Issues: #590, PRs: #739)
  • Fix deep.have.same.members() that was not printing a diff. (PRs: #509)
  • Diff will be shown for assert’s equal and notEqual methods. (Related Issues: #790, PRs: #794)
  • The overwriteMethod, overwriteProperty, addChainableMethod, overwriteChainableMethod functions will return new assertion with flags copied over instead of this. (Related Issues: #562, #642, #791, PRs: #799)

3.5.0 / 2016-01-28

Version 3.5.0

For assert fans: you now have assert.includeDeepMembers() which matches expect().to.include.deep.members() and .should.include.deep.members()!

This release also includes a variety of small bugfixes and documentation fixes. Most notably, we are now governed by a Code Of Conduct - which gives Chai contributors (including those who files issues, work on code, or documentation, or even just hang out on our Slack & Gitter channels) safety from harassment and discrimination.

Full changes below:

Community Contributions

Documentation fixes

3.4.2 / 2015-11-15

Version 3.4.2

This is a small documentation bug fix release - it adds extra metatags to each public method to allow us to generate the docs easier for the website.

Community Contributions

Documentation fixes

3.4.1 / 2015-11-07

Version 3.4.1

This is a small documentation bug fix release - it just fixes a couple of issues with the documentation.

Community Contributions

Documentation fixes

3.4.0 / 2015-10-21

Version 3.4.0

This release improves some confusing error messages, and adds some new assertions. Key points:

  • Feature: New assertion: expect(1).oneOf([1,2,3]) - for asserting that a given value is one of a set.
  • Feature: .include() (and variants) will now give better error messages for bad object types. Before expect(undefined).to.include(1) would say “expected undefined to include 1”, now says “object tested must be an array, an object, or a string but undefined given”
  • Feature: .throw() (and variants) can now better determine the Error types, for example expect(foo).to.throw(node_assert.AssertionError) now works.
  • Feature: .closeTo is now aliased as .approximately
  • BugFix: .empty changes from 3.3.0 have been reverted, as they caused breaking changes to arrays which manually set keys.

Community Contributions

Code Features & Fixes

  • #503 Checking that argument given to expect is of the right type when using with include. By @astorije
  • #446 Make chai able to cope with AssertionErrors raised from node’s assert. By @danielbprice
  • #527 Added approximately alias to close to. By @danielbprice
  • #534 expect(inList) assertion. By @Droogans
  • #538 Revert .empty assertion change from PR #499. By @tusbar

Documentation fixes

3.3.0 / 2015-09-08

Version 3.3.0

This release adds some new assertions and fixes some quite important, long standing bugs. Here are the cliff notes:

  • Bugfix: Property assertions that fail now show a stack trace!
  • Bugfix: If you’ve used the frozen, sealed or extensible assertions to test primitives (e.g. expect(1), you may have noticed that in older browsers (ES5) these fail, and in new ones (ES6) they pass. They have now been fixed to consistently pass
  • The assert interface has been given the following new methods, to align better with other interfaces:, assert.isAtMost, assert.isAtLeast, assert.isNotTrue, assert.isNotFalse.

Community Contributions

Code Features & Fixes

Documentation fixes

3.2.0 / 2015-07-19

Version 3.2.0

This release fixes a bug with the previous additions in 3.1.0. assert.frozen/expect() all accidentally called Object.isSealed() instead. Now they correctly call Object.isFrozen().

If you’re using these features, please upgrade immediately.

It also adds aliases for a lot of assert methods:

  • expect/should..respondTo: respondsTo
  • expect/should..satisfy: satisfies
  • assert.ok: assert.isOk
  • assert.notOk: assert.isNotOk
  • assert.extensible: assert.isExtensible
  • assert.notExtensible: assert.isNotExtensible
  • assert.sealed: assert.isSealed
  • assert.notSealed: assert.isNotSealed
  • assert.frozen: assert.isFrozen
  • assert.notFrozen: assert.isNotFrozen

Community Contributions

Code Features & Fixes

3.1.0 / 2015-07-16

Version 3.1.0

This release adds assertions for extensibility/freezing/sealing on objects:




It also adds assertions for checking if a number is NaN:


Community Contributions

Code Features & Fixes

3.0.0 / 2015-06-04

Version 3.0.0

This release contains some small breaking changes. Most people are unlikely to notice them - but here are the breaking changes:

  • Switched from “Component” builds to “Browserify” builds for Browsers. If you’re using RequireJS with Chai, you might notice a change (chai used to be a global, now it won’t be - instead you’ll have to require it).
  •'foo', undefined) will now specifically test to make sure that the value 'foo' is actually undefined - before it simply tested that the key existed (but could have a value).
  •'type') has changed to support more types, including ES6 types such as 'promise', 'symbol', 'float32array' etc, this also means using ES6’s Symbol.toStringTag affects the behaviour In addition to this, Errors have the type of 'error'.
  • assert.ifError() now follows Node’s assert.ifError() behaviour - in other words, if the first argument is truthy, it’ll throw it.
  • is no longer maintained, see the Github Releases Page instead.
  • is no longer maintained, see the Github Commit Log instead.

Community Contributions

Code Features & Fixes

Documentation fixes

2.3.0 / 2015-04-26

Version 2.3.0

Added ownPropertyDescriptor assertion:

expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 });
expect('test')'length', { enumerable: false, configurable: false, writable: false, value: 3 });
expect('test').ownPropertyDescriptor('length')'enumerable', false);

Community Contributions

Code Features & Fixes

Documentation fixes

2.2.0 / 2015-03-26

Version 2.2.0

Deep property strings can now be escaped using \\ - for example:

var deepCss = { '.link': { '[target]': 42 }};
expect(deepCss)'\\.link.\\[target\\]', 42)

Community Contributions

Code Features & Fixes

Documentation fixes

  • #405 Tweak documentation around deep property escaping. By @keithamus

2.1.2 / 2015-03-15

Version 2.1.2

A minor bug fix. No new features.

Community Contributions

Code Features & Fixes

2.1.1 / 2015-03-04

Version 2.1.1

Two minor bugfixes. No new features.

Community Contributions

Code Features & Fixes

  • #385 Fix a bug (also described in #387) where would not work with single key names. By @eldritch-fossicker
  • #379 Fix bug where tools which overwrite primitive prototypes, such as Babel or core-js would fail. By @dcneiner

Documentation fixes

2.1.0 / 2015-02-23

Version 2.1.0

Small release; fixes an issue where the Chai lib was incorrectly reporting the version number.

Adds new and methods, which are convenience methods to throw Assertion Errors.

Community Contributions

Code Features & Fixes

2.0.0 / 2015-02-09

Version 2.0.0

Unfortunately with 1.10.0 - compatibility broke with older versions because of the addChainableNoop. This change has been reverted.

Any plugins using addChainableNoop should cease to do so.

Any developers wishing for this behaviour can use dirty-chai by @joshperry

Community Contributions

Code Features & Fixes

Documentation fixes

1.10.0 / 2014-11-10

Version 1.10.0

The following changes are required if you are upgrading from the previous version:

  • Users:
    • No changes required
  • Plugin Developers:
    • Review addChainableNoop notes below.
  • Core Contributors:
    • Refresh node_modules folder for updated dependencies.

Noop Function for Terminating Assertion Properties

The following assertions can now also be used in the function-call form:

  • ok
  • true
  • false
  • null
  • undefined
  • exist
  • empty
  • arguments
  • Arguments

The above list of assertions are property getters that assert immediately on access. Because of that, they were written to be used by terminating the assertion chain with a property access.


This syntax is definitely aesthetically pleasing but, if you are linting your test code, your linter will complain with an error something like “Expected an assignment or function call and instead saw an expression.” Since the linter doesn’t know about the property getter it assumes this line has no side-effects, and throws a warning in case you made a mistake.

Squelching these errors is not a good solution as test code is getting to be just as important as, if not more than, production code. Catching syntactical errors in tests using static analysis is a great tool to help make sure that your tests are well-defined and free of typos.

A better option was to provide a function-call form for these assertions so that the code’s intent is more clear and the linters stop complaining about something looking off. This form is added in addition to the existing property access form and does not impact existing test code.


These forms can also be mixed in any way, these are all functionally identical:


Plugin Authors

If you would like to provide this function-call form for your terminating assertion properties, there is a new function to register these types of asserts. Instead of using addProperty to register terminating assertions, simply use addChainableNoop instead; the arguments to both are identical. The latter will make the assertion available in both the attribute and function-call forms and should have no impact on existing users of your plugin.

Community Contributions

Thank you to all who took time to contribute!

1.9.2 / 2014-09-29

Version 1.9.2

The following changes are required if you are upgrading from the previous version:

  • Users:
    • No changes required
  • Plugin Developers:
    • No changes required
  • Core Contributors:
    • Refresh node_modules folder for updated dependencies.

Community Contributions

Thank you to all who took time to contribute!

1.9.1 / 2014-03-19

Version 1.9.1

The following changes are required if you are upgrading from the previous version:

  • Users:
    • Migrate configuration options to new interface. (see notes)
  • Plugin Developers:
    • No changes required
  • Core Contributors:
    • Refresh node_modules folder for updated dependencies.


There have been requests for changes and additions to the configuration mechanisms and their impact in the Chai architecture. As such, we have decoupled the configuration from the Assertion constructor. This not only allows for centralized configuration, but will allow us to shift the responsibility from the Assertion constructor to the assert interface in future releases.

These changes have been implemented in a non-breaking way, but a depretiation warning will be presented to users until they migrate. The old config method will be removed in either v1.11.0 or v2.0.0, whichever comes first.

Quick Migration

// change this:
chai.Assertion.includeStack = true;
chai.Assertion.showDiff = false;

// ... to this:
chai.config.includeStack = true;
chai.config.showDiff = false;

All Config Options

  • @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.

  • @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.

config.truncateThreshold (NEW)
  • @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

Community Contributions

Thank you to all who took time to contribute!

Other Bug Fixes

  • #183 Allow undefined for actual. (internal api)
  • Update Karam(+plugins)/Istanbul to most recent versions.

1.9.0 / 2014-01-29

Version 1.9.0

The following changes are required if you are upgrading from the previous version:

  • Users:
    • No changes required
  • Plugin Developers:
  • Core Contributors:
    • Refresh node_modules folder for updated dependencies.

Community Contributions

Thank you to all who took time to contribute!

Other Bug Fixes

  • #225 Improved AMD wrapper provided by upstream component(1).
  • #185 assert.throws() returns thrown error for further assertions.
  • #237 Remove coveralls/jscoverage, include istanbul coverage report in travis test.
  • Update Karma and Sauce runner versions for consistent CI results. No more karma@canary.