Skip to content

Releases: chaijs/chai

4.0.0 / 2017-05-26

26 May 10:29
Compare
Choose a tag to compare

4.0.0

4.0 has been a huge undertaking by the chai community! A lot has changed to ensure Chai 4 is a stable, reliable, well documented codebase. Here are just some of the major improvements:

  • almost all documentation has been rewritten, with detailed instructions on how assertions work, which flags they can be combined with and the best practices for how to use them.

  • deep equality has been rewritten from the ground up to support ES6 types like Map and Set, and better support existing types. It is now also much, much faster than before and allows us to bring some great improvements in upcoming releases.

  • we have made sure the deep flag now only ever does deep equality. Beforehand, it would sometimes also be used to test nested properties (for example expect(foo).to.have.deep.property('bar.baz'). For nested assertions, please now use the .nested flag.

  • many assertions have become more strict, which means you get better error messages explaining where things have gone wrong. For the most part, this wont mean error messages where there weren't error messages before, but it will mean better error messages to replace the, sometimes cryptic, default TypeError messages.

  • we've added detections and helpful error messages for common mistakes and typos. The error messages will, in some cases, point you to documentation or in other cases suggest alternatives. These messages will continue to be improved in future releases, so let us know if you have any suggestions!

Breaking Changes

  • We no longer support Node v0.10 and v0.12 (since their LTS has ended) (PRs: #816, #901)

  • 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}).to.have.deep.property('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}).to.have.nested.property('foo.a', 1);
    
    // You can also use both flags combined
    const obj2 = {a: {b: 2}};
    expect({foo: obj2}).to.have.deep.nested.property('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).not.property(name, 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([obj]).to.deep.include({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
    expect(NaN).to.be.NaN;
    
    // Anything that is not `NaN` cannot be considered as `NaN`
    expect('randomString').not.to.be.NaN;
    expect(true).not.to.be.NaN;
    expect({}).not.to.be.NaN;
    expect(4).not.to.be.NaN;
  • 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++) {
      arr.push(i);
    }
    
    // The assertion below will truncate the diff shown and the enormous 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).to.be.within(0, 1);
    expect(null).to.be.above(10);
    expect(null).to.be.at.least(20);
    expect(null).to.be.below(20);
    expect(null).to.be.at.most(20);
    expect(null).to.increase.by(20);
    expect(null).to.decrease.by(20);
    
    // This will not:
    expect('string').to.have.a.lengthOf.at.least(3);
  • 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' }).to.not.have.own.property('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(Symbol()).to.be.empty;
    expect(function() {}).to.be.empty;
    expect(true).to.be.empty;
    expect(1).to.be.empty
  • Assertion subject (obj) changes when using ownProperty or own.property and thus enables chaining. (Related Issues: #281, PRs: #641)

    expect({val: 20}).to.have.own.property('val').above(10);
  • The .change, .increase, and .decrease assertions changed from chainable method assertions to method assertions. They don't have any chaining behavior, and there's no generic semantic benefit to chaining them. (Related Issues: #917, PRs: #925)

// This will not work anymore because there is no benefit to chaining these assertions:
expect(function() {}).to.change.by(2)
expect(function() {}).to.increase.by(2)
expect(function() {}).to.decrease.by(2)
  • 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)

  • (For plugin authors) 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
    expect('anything').to.imaginaryMethod(); 
  • (For plugin authors) 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) {
      assert.isTrue(e.showDiff);
    }
    
    // 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) {
      assert.isFalse(e.showDiff);
    }

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).to.be.ture; // 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 disable...

Read more

4.0.0-canary.2 / 2017-04-17

17 Apr 18:03
Compare
Choose a tag to compare
Pre-release

4.0.0-canary.2 / 2017-04-17

The second release in the 4.0.0 canary release cycle. Around the end of April, barring any showstopper bugs, this will be released as 4.0.0

Breaking Changes

  • We've dropped support for Node 0.10 (See #816) and Node 0.12 (#901). The minimum supported version is now Node 4.0. If you wish to continue using older versions of Node with Chai, please continue to use the 3.5.0 release. Officially, version 4.0.0 of chai supports Nodes 4, 6, 7, as well as the moving LTS version (currently 6.10.2). We plan to support Node 4 until at-least April 2018 (inline with Node Foundation support).

  • .not.keys on its own is now the equivalent of .not.all.keys (#924). The docs mention this, and suggest to always pair .keys with something.

New Features

  • Added side-effectful "register" style scripts for each interface, (See #868). This allows one to require('chai/should') which will automatically call global.should = chai.should(). This is useful for users who wish to automatically get a global for their codebase. Read the docs for more info!

  • Added the browser field to the package json (#875). This will help with browser bundling tools.

  • Added .own.include and .nested.include (#926).

  • If you attempt to call .throws with something that isn't a constructor (like TypeError) you will now get a more helpful error message about this. (before it would say Right-hand side of 'instanceof' is not an object, now it says The instanceof assertion needs a constructor but <type> was given). (#899).

Bug Fixes

  • Minor update deep-eql to 2.0.1 (#871) which fixes bugs around Memoization, and lets comparators override evaluation of primitives.

  • We've updated documentation and error handling around using .length (#897) - which can, in some cases, be problematic. Typically, you'll want to use .lengthOf instead - but the documentation now makes this clear, and errors are more helpful when bad things happen.

  • We've improved stack traces to strip out chai's internals, especially in newer environments which use Proxies (#884 and #922).

  • We've gone through and made sure every assertion honors the custom error message you pass it - some didn't! (#947).

  • getFuncName has had an update since we pulled out the behaviour in 4.0.0-canary.1 (#915). Practically this doesn't change anything in Chai.

Documentation

  • Added LICENSE file (#854)
  • Major documentation rewrite including the plugin docs (#911), .throw docs (#866), and, well, just about all other docs (#920). These docs are far more detailed now, explaining caveats, algorithms and best practices.

4.0.0-canary.1

24 Oct 22:09
Compare
Choose a tag to compare
4.0.0-canary.1 Pre-release
Pre-release

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}).to.have.deep.property('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}).to.have.nested.property('foo.a', 1);
    
    // You can also use both flags combined
    const obj2 = {a: {b: 2}};
    expect({foo: obj2}).to.have.deep.nested.property('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).not.property(name, 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([obj]).to.deep.include({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
    expect(NaN).to.be.NaN;
    
    // Anything that is not `NaN` cannot be considered as `NaN`
    expect('randomString').not.to.be.NaN;
    expect(true).not.to.be.NaN;
    expect({}).not.to.be.NaN;
    expect(4).not.to.be.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
    expect('anything').to.imaginaryMethod(); 
  • 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) {
      assert.isTrue(e.showDiff);
    }
    
    // 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) {
      assert.isFalse(e.showDiff);
    }
  • 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++) {
      arr.push(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).to.be.within(0, 1);
    expect(null).to.be.above(10);
    expect(null).to.be.at.least(20);
    expect(null).to.be.below(20);
    expect(null).to.be.at.most(20);
    expect(null).to.increase.by(20);
    expect(null).to.decrease.by(20);
    
    // This will not:
    expect('string').to.have.a.length.of.at.least(3);
  • 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' }).to.not.have.own.property('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(Symbol()).to.be.empty;
    expect(function() {}).to.be.empty;
    expect(true).to.be.empty;
    expect(1).to.be.empty
  • Assertion subject (obj) changes when using ownProperty or own.property and thus enables chaining. (Related Issues: #281, PRs: #641)

    expect({val: 20}).to.have.own.property('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).to.be.ture; // 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).to.be.fals; // Error: Invalid Chai property: fals. Did you mean "false"?
    expect('foo').to.be.undefind; // 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').to.be.fdsakfdsafsagsadgagsdfasf // 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)

    chai.config.proxyExcludedKeys.push('nonExistingProp');
    
    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';
    should();

    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
    assert.increases(
      someOperation,
      () => getSomething().length
    )
  • You can ...

Read more

3.5.0 / 2016-01-28

28 Jan 12:02
Compare
Choose a tag to compare

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

15 Nov 22:50
Compare
Choose a tag to compare

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

07 Nov 23:22
Compare
Choose a tag to compare

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

21 Oct 11:12
Compare
Choose a tag to compare

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).to.be.oneOf assertion. By @Droogans
  • #538 Revert .empty assertion change from PR #499. By @tusbar

Documentation fixes

3.3.0 / 2015-09-08

11 Sep 21:42
Compare
Choose a tag to compare

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).to.be.frozen), 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

19 Jul 17:02
Compare
Choose a tag to compare

This release fixes a bug with the previous additions in 3.1.0. assert.frozen/expect().to.be.frozen/.should.be.frozen 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

16 Jul 21:06
Compare
Choose a tag to compare

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

assert.extensible({});
assert.notExtensible(Object.preventExtensions({}));
expect(Object.preventExtensions({})).to.not.be.extensible;
Object.preventExtensions({}).should.not.be.extensible;

assert.notSealed({});
assert.sealed(Object.seal({}));
expect(Object.seal({})).to.be.sealed;
Object.seal({}).should.be.sealed;

assert.notFrozen({});
assert.frozen(Object.freeze({}));
expect(Object.freeze({})).to.be.frozen;
Object.freeze({}).should.be.frozen;

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

assert.isNaN(NaN);
assert.isNotNaN(5);
expect(NaN).to.be.NaN;
expect(5).to.not.be.NaN;
NaN.should.be.NaN;
5.should.not.be.NaN;

Community Contributions

Code Features & Fixes