From 984622a4ea0d234536be6343268fb8a1b545005d Mon Sep 17 00:00:00 2001 From: Jake Luer Date: Wed, 18 Sep 2013 15:04:00 -0400 Subject: [PATCH] Release 1.8.0 --- History.md | 17 +- README.md | 78 +++---- ReleaseNotes.md | 57 +++++ bower.json | 2 +- chai.js | 550 ++++++++++++++++++++++++++++++++++++------------ component.json | 2 +- lib/chai.js | 2 +- package.json | 2 +- 8 files changed, 532 insertions(+), 178 deletions(-) diff --git a/History.md b/History.md index faed05a..165d7d2 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,19 @@ +1.8.0 / 2013-09-18 +================== + + * test: [sauce] add a few more browsers + * Merge branch 'refactor/deep-equal' + * util: remove embedded deep equal utility + * util: replace embedded deep equal with external module + * Merge branch 'feature/karma' + * docs: add sauce badge to readme [ci skip] + * test: [sauce] use karma@canary to prevent timeouts + * travis: only run on node 0.10 + * test: [karma] use karma phantomjs runner + * Merge pull request #181 from tricknotes/fix-highlight + * Fix highlight for example code + 1.7.2 / 2013-06-27 ================== @@ -47,7 +62,7 @@ * Downgrade mocha version for fix running Phantom tests. * Fix comparison equality of two regexps. * Merge pull request #161 from brandonpayton/master - * Fix documented name for assert interface's isDefined method + * Fix documented name for assert interfaces isDefined method 1.6.0 / 2013-04-29 ================== diff --git a/README.md b/README.md index 95c770e..0a390fc 100644 --- a/README.md +++ b/README.md @@ -11,48 +11,48 @@ For more information or to download plugins, view the [documentation](http://cha ### Related Projects -- [@chaijs/assertion-error](https://github.com/chaijs/assertion-error): Custom `Error` constructor -thrown upon an assertion failing. +- [chaijs / assertion-error](https://github.com/chaijs/assertion-error): Custom `Error` constructor thrown upon an assertion failing. +- [chaijs / deep-eql](https://github.com/chaijs/deep-eql): Improved deep equality testing for Node.js and the browser. ### Contributors - project : chai - repo age : 1 year, 7 months - active : 136 days - commits : 678 - files : 55 - authors : - 504 Jake Luer 74.3% - 66 Veselin Todorov 9.7% - 43 Domenic Denicola 6.3% - 6 Ruben Verborgh 0.9% - 5 Juliusz Gonera 0.7% - 5 George Kats 0.7% - 5 Scott Nonnenberg 0.7% - 5 Jo Liss 0.7% - 4 John Firebaugh 0.6% - 4 josher19 0.6% - 4 Nick Heiner 0.6% - 3 Jeff Barczewski 0.4% - 2 Ryunosuke SATO 0.3% - 2 Bartvds 0.3% - 2 Teddy Cross 0.3% - 2 Edwin Shao 0.3% - 2 Jakub Nešetřil 0.3% - 1 piecioshka 0.1% - 1 Benjamin Horsleben 0.1% - 1 Brandon Payton 0.1% - 1 Chris Connelly 0.1% - 1 Chun-Yi 0.1% - 1 DD 0.1% - 1 Jeff Welch 0.1% - 1 Kilian Ciuffolo 0.1% - 1 Niklas Närhinen 0.1% - 1 Paul Miller 0.1% - 1 Sasha Koss 0.1% - 1 Victor Costan 0.1% - 1 Vinay Pulim 0.1% - 1 Anand Patil 0.1% + project : chai + repo age : 1 year, 9 months + active : 139 days + commits : 693 + files : 54 + authors : + 518 Jake Luer 74.7% + 66 Veselin Todorov 9.5% + 43 Domenic Denicola 6.2% + 6 Ruben Verborgh 0.9% + 5 George Kats 0.7% + 5 Jo Liss 0.7% + 5 Juliusz Gonera 0.7% + 5 Scott Nonnenberg 0.7% + 4 John Firebaugh 0.6% + 4 Nick Heiner 0.6% + 4 josher19 0.6% + 3 Jeff Barczewski 0.4% + 3 Ryunosuke SATO 0.4% + 2 Bartvds 0.3% + 2 Edwin Shao 0.3% + 2 Jakub Nešetřil 0.3% + 2 Teddy Cross 0.3% + 1 Anand Patil 0.1% + 1 Benjamin Horsleben 0.1% + 1 Brandon Payton 0.1% + 1 Chris Connelly 0.1% + 1 Chun-Yi 0.1% + 1 DD 0.1% + 1 Jeff Welch 0.1% + 1 Kilian Ciuffolo 0.1% + 1 Niklas Närhinen 0.1% + 1 Paul Miller 0.1% + 1 Sasha Koss 0.1% + 1 Victor Costan 0.1% + 1 Vinay Pulim 0.1% + 1 piecioshka 0.1% ## License diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 4a76966..362fe57 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,62 @@ # Release Notes +## 1.8.0 / 2013-09-18 + +The following changes are required if you are upgrading from the previous version: + +- **Users:** + - See `deep.equal` notes. +- **Plugin Developers:** + - No changes required +- **Core Contributors:** + - Refresh `node_modules` folder for updated dependencies. + +### Deep Equals + +This version of Chai focused on a overhaul to the deep equal utility. The code for this +tool has been removed from the core lib and can now be found at: +[chai / deep-eql](https://github.com/chaijs/deep-eql). As stated in previous releases, +this is part of a larger initiative to provide transparency, independent testing, and coverage for +some of the more complicated internal tools. + +For the most part `.deep.equal` will behave the same as it has. However, in order to provide a +consistent ruleset across all types being tested, the following changes have been made and _might_ +require changes to your tests. + +**1.** Strict equality for non-traversable nodes according to [egal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + +_Previously:_ Non-traversable equal via `===`. + +```js +expect(NaN).to.deep.equal(NaN); +expect(-0).to.not.deep.equal(+0); +``` + +**2.** Arguments are not Arrays (and all types must be equal): + +_Previously:_ Some crazy nonsense that led to empty arrays deep equaling empty objects deep equaling dates. + +```js +expect(arguments).to.not.deep.equal([]); +expect(Array.prototype.slice.call(arguments)).to.deep.equal([]); +``` + +- [#156](https://github.com/chaijs/chai/issues/156) Empty object is eql to empty array +- [#192](https://github.com/chaijs/chai/issues/192) empty object is eql to a Date object +- [#194](https://github.com/chaijs/chai/issues/194) refactor deep-equal utility + +### CI and Browser Testing + +Chai now runs the browser CI suite using [Karma](http://karma-runner.github.io/) directed at +[SauceLabs](https://saucelabs.com/). This means we get to know where our browser support stands... +and we get a cool badge: + +[![Selenium Test Status](https://saucelabs.com/browser-matrix/logicalparadox.svg)](https://saucelabs.com/u/logicalparadox) + +Look for the list of browsers/versions to expand over the coming releases. + +- [#195](https://github.com/chaijs/chai/issues/195) karma test framework + ## 1.7.2 / 2013-06-27 The following changes are required if you are upgrading from the previous version: diff --git a/bower.json b/bower.json index f7808e7..0279f29 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chai" - , "version": "1.7.2" + , "version": "1.8.0" , "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic." , "license": "MIT" , "keywords": [ diff --git a/chai.js b/chai.js index 097b1d4..2663a50 100644 --- a/chai.js +++ b/chai.js @@ -312,6 +312,411 @@ AssertionError.prototype.toJSON = function (stack) { return props; }; +}); +require.register("chaijs-type-detect/lib/type.js", function(exports, require, module){ +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Array]': 'array' + , '[object RegExp]': 'regexp' + , '[object Function]': 'function' + , '[object Arguments]': 'arguments' + , '[object Date]': 'date' +}; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ + +function getType (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library () { + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function (type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function (obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +}); +require.register("chaijs-deep-eql/lib/eql.js", function(exports, require, module){ +/*! + * deep-eql + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var type = require('type-detect'); + +/*! + * Buffer.isBuffer browser shim + */ + +var Buffer; +try { Buffer = require('buffer').Buffer; } +catch(ex) { + Buffer = {}; + Buffer.isBuffer = function() { return false; } +} + +/*! + * Primary Export + */ + +module.exports = deepEqual; + +/** + * Assert super-strict (egal) equality between + * two objects of any type. + * + * @param {Mixed} a + * @param {Mixed} b + * @param {Array} memoised (optional) + * @return {Boolean} equal match + */ + +function deepEqual(a, b, m) { + if (sameValue(a, b)) { + return true; + } else if ('date' === type(a)) { + return dateEqual(a, b); + } else if ('regexp' === type(a)) { + return regexpEqual(a, b); + } else if (Buffer.isBuffer(a)) { + return bufferEqual(a, b); + } else if ('arguments' === type(a)) { + return argumentsEqual(a, b, m); + } else if (!typeEqual(a, b)) { + return false; + } else if (('object' !== type(a) && 'object' !== type(b)) + && ('array' !== type(a) && 'array' !== type(b))) { + return sameValue(a, b); + } else { + return objectEqual(a, b, m); + } +} + +/*! + * Strict (egal) equality test. Ensures that NaN always + * equals NaN and `-0` does not equal `+0`. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} equal match + */ + +function sameValue(a, b) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + return a !== a && b !== b; +} + +/*! + * Compare the types of two given objects and + * return if they are equal. Note that an Array + * has a type of `array` (not `object`) and arguments + * have a type of `arguments` (not `array`/`object`). + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function typeEqual(a, b) { + return type(a) === type(b); +} + +/*! + * Compare two Date objects by asserting that + * the time values are equal using `saveValue`. + * + * @param {Date} a + * @param {Date} b + * @return {Boolean} result + */ + +function dateEqual(a, b) { + if ('date' !== type(b)) return false; + return sameValue(a.getTime(), b.getTime()); +} + +/*! + * Compare two regular expressions by converting them + * to string and checking for `sameValue`. + * + * @param {RegExp} a + * @param {RegExp} b + * @return {Boolean} result + */ + +function regexpEqual(a, b) { + if ('regexp' !== type(b)) return false; + return sameValue(a.toString(), b.toString()); +} + +/*! + * Assert deep equality of two `arguments` objects. + * Unfortunately, these must be sliced to arrays + * prior to test to ensure no bad behavior. + * + * @param {Arguments} a + * @param {Arguments} b + * @param {Array} memoize (optional) + * @return {Boolean} result + */ + +function argumentsEqual(a, b, m) { + if ('arguments' !== type(b)) return false; + a = [].slice.call(a); + b = [].slice.call(b); + return deepEqual(a, b, m); +} + +/*! + * Get enumerable properties of a given object. + * + * @param {Object} a + * @return {Array} property names + */ + +function enumerable(a) { + var res = []; + for (var key in a) res.push(key); + return res; +} + +/*! + * Simple equality for flat iterable objects + * such as Arrays or Node.js buffers. + * + * @param {Iterable} a + * @param {Iterable} b + * @return {Boolean} result + */ + +function iterableEqual(a, b) { + if (a.length !== b.length) return false; + + var i = 0; + var match = true; + + for (; i < a.length; i++) { + if (a[i] !== b[i]) { + match = false; + break; + } + } + + return match; +} + +/*! + * Extension to `iterableEqual` specifically + * for Node.js Buffers. + * + * @param {Buffer} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function bufferEqual(a, b) { + if (!Buffer.isBuffer(b)) return false; + return iterableEqual(a, b); +} + +/*! + * Block for `objectEqual` ensuring non-existing + * values don't get in. + * + * @param {Mixed} object + * @return {Boolean} result + */ + +function isValue(a) { + return a !== null && a !== undefined; +} + +/*! + * Recursively check the equality of two objects. + * Once basic sameness has been established it will + * defer to `deepEqual` for each enumerable key + * in the object. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function objectEqual(a, b, m) { + if (!isValue(a) || !isValue(b)) { + return false; + } + + if (a.prototype !== b.prototype) { + return false; + } + + var i; + if (m) { + for (i = 0; i < m.length; i++) { + if ((m[i][0] === a && m[i][1] === b) + || (m[i][0] === b && m[i][1] === a)) { + return true; + } + } + } else { + m = []; + } + + try { + var ka = enumerable(a); + var kb = enumerable(b); + } catch (ex) { + return false; + } + + ka.sort(); + kb.sort(); + + if (!iterableEqual(ka, kb)) { + return false; + } + + m.push([ a, b ]); + + var key; + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], m)) { + return false; + } + } + + return true; +} + }); require.register("chai/index.js", function(exports, require, module){ module.exports = require('./lib/chai'); @@ -331,7 +736,7 @@ var used = [] * Chai version */ -exports.version = '1.7.2'; +exports.version = '1.8.0'; /*! * Assertion Error @@ -3162,138 +3567,6 @@ module.exports = function (ctx, name, getter) { }); }; -}); -require.register("chai/lib/chai/utils/eql.js", function(exports, require, module){ -// This is (almost) directly from Node.js assert -// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js - -module.exports = _deepEqual; - -var getEnumerableProperties = require('./getEnumerableProperties'); - -// for the browser -var Buffer; -try { - Buffer = require('buffer').Buffer; -} catch (ex) { - Buffer = { - isBuffer: function () { return false; } - }; -} - -function _deepEqual(actual, expected, memos) { - - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } - - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (expected instanceof Date) { - if (!(actual instanceof Date)) return false; - return actual.getTime() === expected.getTime(); - - // 7.3. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (typeof actual != 'object' && typeof expected != 'object') { - return actual === expected; - - } else if (expected instanceof RegExp) { - if (!(actual instanceof RegExp)) return false; - return actual.toString() === expected.toString(); - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected, memos); - } -} - -function isUndefinedOrNull(value) { - return value === null || value === undefined; -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b, memos) { - if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) - return false; - - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - - // check if we have already compared a and b - var i; - if (memos) { - for(i = 0; i < memos.length; i++) { - if ((memos[i][0] === a && memos[i][1] === b) || - (memos[i][0] === b && memos[i][1] === a)) - return true; - } - } else { - memos = []; - } - - //~~~I've managed to break Object.keys through screwy arguments passing. - // Converting to array solves the problem. - if (isArguments(a)) { - if (!isArguments(b)) { - return false; - } - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b, memos); - } - try { - var ka = getEnumerableProperties(a), - kb = getEnumerableProperties(b), - key; - } catch (e) {//happens when one is a string literal and the other isn't - return false; - } - - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - - // remember objects we have compared to guard against circular references - memos.push([ a, b ]); - - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key], memos)) return false; - } - - return true; -} - }); require.register("chai/lib/chai/utils/flag.js", function(exports, require, module){ /*! @@ -3663,7 +3936,7 @@ exports.transferFlags = require('./transferFlags'); * Deep equal utility */ -exports.eql = require('./eql'); +exports.eql = require('deep-eql'); /*! * Deep path value @@ -4318,10 +4591,19 @@ module.exports = function (obj) { }; }); + + require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js"); require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js"); require.alias("chaijs-assertion-error/index.js", "assertion-error/index.js"); require.alias("chaijs-assertion-error/index.js", "chaijs-assertion-error/index.js"); +require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/lib/eql.js"); +require.alias("chaijs-deep-eql/lib/eql.js", "chai/deps/deep-eql/index.js"); +require.alias("chaijs-deep-eql/lib/eql.js", "deep-eql/index.js"); +require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/lib/type.js"); +require.alias("chaijs-type-detect/lib/type.js", "chaijs-deep-eql/deps/type-detect/index.js"); +require.alias("chaijs-type-detect/lib/type.js", "chaijs-type-detect/index.js"); +require.alias("chaijs-deep-eql/lib/eql.js", "chaijs-deep-eql/index.js"); require.alias("chai/index.js", "chai/index.js");if (typeof exports == "object") { module.exports = require("chai"); } else if (typeof define == "function" && define.amd) { diff --git a/component.json b/component.json index 1ec709c..094f58c 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "name": "chai" , "repo": "chaijs/chai" - , "version": "1.7.2" + , "version": "1.8.0" , "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic." , "license": "MIT" , "keywords": [ diff --git a/lib/chai.js b/lib/chai.js index 6c85f6e..e58b857 100644 --- a/lib/chai.js +++ b/lib/chai.js @@ -11,7 +11,7 @@ var used = [] * Chai version */ -exports.version = '1.7.2'; +exports.version = '1.8.0'; /*! * Assertion Error diff --git a/package.json b/package.json index e60ab91..9372d20 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "Veselin Todorov ", "John Firebaugh " ], - "version": "1.7.2", + "version": "1.8.0", "repository": { "type": "git", "url": "https://github.com/chaijs/chai"