diff --git a/.jscs.json b/.jscs.json index f00a97b9..0e043abb 100644 --- a/.jscs.json +++ b/.jscs.json @@ -149,6 +149,10 @@ "requireObjectDestructuring": false, - "requireEarlyReturn": false + "requireEarlyReturn": false, + + "requireCapitalizedConstructorsNew": { + "allExcept": ["Function", "String", "Object", "Symbol", "Number", "Date", "RegExp", "Error", "Boolean", "Array", "OrigNumber"] + } } diff --git a/node_modules/chai/chai.js b/node_modules/chai/chai.js index 431fea3f..1d30296a 100644 --- a/node_modules/chai/chai.js +++ b/node_modules/chai/chai.js @@ -15,7 +15,7 @@ var used = [] * Chai version */ -exports.version = '3.4.1'; +exports.version = '3.5.0'; /*! * Assertion Error @@ -324,6 +324,7 @@ module.exports = function (chai, _) { * - same * * @name language chains + * @namespace BDD * @api public */ @@ -347,6 +348,7 @@ module.exports = function (chai, _) { * .and.not.equal('bar'); * * @name not + * @namespace BDD * @api public */ @@ -371,6 +373,7 @@ module.exports = function (chai, _) { * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); * * @name deep + * @namespace BDD * @api public */ @@ -387,6 +390,7 @@ module.exports = function (chai, _) { * expect(foo).to.have.any.keys('bar', 'baz'); * * @name any + * @namespace BDD * @api public */ @@ -405,6 +409,7 @@ module.exports = function (chai, _) { * expect(foo).to.have.all.keys('bar', 'baz'); * * @name all + * @namespace BDD * @api public */ @@ -440,6 +445,7 @@ module.exports = function (chai, _) { * @alias an * @param {String} type * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -477,6 +483,7 @@ module.exports = function (chai, _) { * @alias contains * @param {Object|String|Number} obj * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -532,6 +539,7 @@ module.exports = function (chai, _) { * expect(null).to.not.be.ok; * * @name ok + * @namespace BDD * @api public */ @@ -551,6 +559,7 @@ module.exports = function (chai, _) { * expect(1).to.not.be.true; * * @name true + * @namespace BDD * @api public */ @@ -572,6 +581,7 @@ module.exports = function (chai, _) { * expect(0).to.not.be.false; * * @name false + * @namespace BDD * @api public */ @@ -593,6 +603,7 @@ module.exports = function (chai, _) { * expect(undefined).to.not.be.null; * * @name null + * @namespace BDD * @api public */ @@ -613,6 +624,7 @@ module.exports = function (chai, _) { * expect(null).to.not.be.undefined; * * @name undefined + * @namespace BDD * @api public */ @@ -632,6 +644,7 @@ module.exports = function (chai, _) { * expect(4).not.to.be.NaN; * * @name NaN + * @namespace BDD * @api public */ @@ -657,6 +670,7 @@ module.exports = function (chai, _) { * expect(baz).to.not.exist; * * @name exist + * @namespace BDD * @api public */ @@ -681,6 +695,7 @@ module.exports = function (chai, _) { * expect({}).to.be.empty; * * @name empty + * @namespace BDD * @api public */ @@ -712,6 +727,7 @@ module.exports = function (chai, _) { * * @name arguments * @alias Arguments + * @namespace BDD * @api public */ @@ -747,6 +763,7 @@ module.exports = function (chai, _) { * @alias deep.equal * @param {Mixed} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -783,6 +800,7 @@ module.exports = function (chai, _) { * @alias eqls * @param {Mixed} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -821,6 +839,7 @@ module.exports = function (chai, _) { * @alias greaterThan * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -869,6 +888,7 @@ module.exports = function (chai, _) { * @alias gte * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -917,6 +937,7 @@ module.exports = function (chai, _) { * @alias lessThan * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -965,6 +986,7 @@ module.exports = function (chai, _) { * @alias lte * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1012,6 +1034,7 @@ module.exports = function (chai, _) { * @param {Number} start lowerbound inclusive * @param {Number} finish upperbound inclusive * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1051,6 +1074,7 @@ module.exports = function (chai, _) { * @param {Constructor} constructor * @param {String} message _optional_ * @alias instanceOf + * @namespace BDD * @api public */ @@ -1135,6 +1159,7 @@ module.exports = function (chai, _) { * @param {Mixed} value (optional) * @param {String} message _optional_ * @returns value of property for chaining + * @namespace BDD * @api public */ @@ -1190,6 +1215,7 @@ module.exports = function (chai, _) { * @alias haveOwnProperty * @param {String} name * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1222,6 +1248,7 @@ module.exports = function (chai, _) { * @param {String} name * @param {Object} descriptor _optional_ * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1274,6 +1301,7 @@ module.exports = function (chai, _) { * switched to use `lengthOf(value)` instead. * * @name length + * @namespace BDD * @api public */ @@ -1289,6 +1317,7 @@ module.exports = function (chai, _) { * @name lengthOf * @param {Number} length * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1325,6 +1354,7 @@ module.exports = function (chai, _) { * @alias matches * @param {RegExp} RegularExpression * @param {String} message _optional_ + * @namespace BDD * @api public */ function assertMatch(re, msg) { @@ -1350,6 +1380,7 @@ module.exports = function (chai, _) { * @name string * @param {String} string * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1401,6 +1432,7 @@ module.exports = function (chai, _) { * @name keys * @alias key * @param {...String|Array|Object} keys + * @namespace BDD * @api public */ @@ -1520,6 +1552,7 @@ module.exports = function (chai, _) { * @param {String} message _optional_ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types * @returns error for chaining (null if no error) + * @namespace BDD * @api public */ @@ -1663,6 +1696,7 @@ module.exports = function (chai, _) { * @alias respondsTo * @param {String} method * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1697,6 +1731,7 @@ module.exports = function (chai, _) { * expect(Foo).itself.not.to.respondTo('baz'); * * @name itself + * @namespace BDD * @api public */ @@ -1715,6 +1750,7 @@ module.exports = function (chai, _) { * @alias satisfies * @param {Function} matcher * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1746,6 +1782,7 @@ module.exports = function (chai, _) { * @param {Number} expected * @param {Number} delta * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1797,6 +1834,7 @@ module.exports = function (chai, _) { * @name members * @param {Array} set * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1846,6 +1884,7 @@ module.exports = function (chai, _) { * @name oneOf * @param {Array<*>} list * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1875,7 +1914,7 @@ module.exports = function (chai, _) { * 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') + * expect(noChangeFn).to.not.change(obj, 'val') * * @name change * @alias changes @@ -1883,6 +1922,7 @@ module.exports = function (chai, _) { * @param {String} object * @param {String} property name * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1920,6 +1960,7 @@ module.exports = function (chai, _) { * @param {String} object * @param {String} property name * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1957,6 +1998,7 @@ module.exports = function (chai, _) { * @param {String} object * @param {String} property name * @param {String} message _optional_ + * @namespace BDD * @api public */ @@ -1995,6 +2037,7 @@ module.exports = function (chai, _) { * expect(frozenObject).to.not.be.extensible; * * @name extensible + * @namespace BDD * @api public */ @@ -2036,6 +2079,7 @@ module.exports = function (chai, _) { * expect({}).to.not.be.sealed; * * @name sealed + * @namespace BDD * @api public */ @@ -2075,6 +2119,7 @@ module.exports = function (chai, _) { * expect({}).to.not.be.frozen; * * @name frozen + * @namespace BDD * @api public */ @@ -2135,6 +2180,7 @@ module.exports = function (chai, util) { * @param {Mixed} expression to test for truthiness * @param {String} message to display on error * @name assert + * @namespace Assert * @api public */ @@ -2157,6 +2203,7 @@ module.exports = function (chai, util) { * @param {Mixed} expected * @param {String} message * @param {String} operator + * @namespace Assert * @api public */ @@ -2181,6 +2228,7 @@ module.exports = function (chai, util) { * @alias ok * @param {Mixed} object to test * @param {String} message + * @namespace Assert * @api public */ @@ -2200,6 +2248,7 @@ module.exports = function (chai, util) { * @alias notOk * @param {Mixed} object to test * @param {String} message + * @namespace Assert * @api public */ @@ -2218,6 +2267,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2244,6 +2294,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2270,6 +2321,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2288,6 +2340,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2306,6 +2359,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2324,6 +2378,7 @@ module.exports = function (chai, util) { * @param {Mixed} actual * @param {Mixed} expected * @param {String} message + * @namespace Assert * @api public */ @@ -2342,6 +2397,7 @@ module.exports = function (chai, util) { * @param {Mixed} valueToCheck * @param {Mixed} valueToBeAbove * @param {String} message + * @namespace Assert * @api public */ @@ -2361,6 +2417,7 @@ module.exports = function (chai, util) { * @param {Mixed} valueToCheck * @param {Mixed} valueToBeAtLeast * @param {String} message + * @namespace Assert * @api public */ @@ -2379,6 +2436,7 @@ module.exports = function (chai, util) { * @param {Mixed} valueToCheck * @param {Mixed} valueToBeBelow * @param {String} message + * @namespace Assert * @api public */ @@ -2398,6 +2456,7 @@ module.exports = function (chai, util) { * @param {Mixed} valueToCheck * @param {Mixed} valueToBeAtMost * @param {String} message + * @namespace Assert * @api public */ @@ -2416,6 +2475,7 @@ module.exports = function (chai, util) { * @name isTrue * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2434,6 +2494,7 @@ module.exports = function (chai, util) { * @name isNotTrue * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2452,6 +2513,7 @@ module.exports = function (chai, util) { * @name isFalse * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2470,6 +2532,7 @@ module.exports = function (chai, util) { * @name isNotFalse * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2487,6 +2550,7 @@ module.exports = function (chai, util) { * @name isNull * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2505,6 +2569,7 @@ module.exports = function (chai, util) { * @name isNotNull * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2521,6 +2586,7 @@ module.exports = function (chai, util) { * @name isNaN * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2537,6 +2603,7 @@ module.exports = function (chai, util) { * @name isNotNaN * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ assert.isNotNaN = function (val, msg) { @@ -2554,6 +2621,7 @@ module.exports = function (chai, util) { * @name isUndefined * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2572,6 +2640,7 @@ module.exports = function (chai, util) { * @name isDefined * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2590,6 +2659,7 @@ module.exports = function (chai, util) { * @name isFunction * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2608,6 +2678,7 @@ module.exports = function (chai, util) { * @name isNotFunction * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2618,8 +2689,8 @@ module.exports = function (chai, util) { /** * ### .isObject(value, [message]) * - * Asserts that `value` is an object (as revealed by - * `Object.prototype.toString`). + * Asserts that `value` is an object of type 'Object' (as revealed by `Object.prototype.toString`). + * _The assertion does not match subclassed objects._ * * var selection = { name: 'Chai', serve: 'with spices' }; * assert.isObject(selection, 'tea selection is an object'); @@ -2627,6 +2698,7 @@ module.exports = function (chai, util) { * @name isObject * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2637,7 +2709,7 @@ module.exports = function (chai, util) { /** * ### .isNotObject(value, [message]) * - * Asserts that `value` is _not_ an object. + * Asserts that `value` is _not_ an object of type 'Object' (as revealed by `Object.prototype.toString`). * * var selection = 'chai' * assert.isNotObject(selection, 'tea selection is not an object'); @@ -2646,6 +2718,7 @@ module.exports = function (chai, util) { * @name isNotObject * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2664,6 +2737,7 @@ module.exports = function (chai, util) { * @name isArray * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2682,6 +2756,7 @@ module.exports = function (chai, util) { * @name isNotArray * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2700,6 +2775,7 @@ module.exports = function (chai, util) { * @name isString * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2718,6 +2794,7 @@ module.exports = function (chai, util) { * @name isNotString * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2736,6 +2813,7 @@ module.exports = function (chai, util) { * @name isNumber * @param {Number} value * @param {String} message + * @namespace Assert * @api public */ @@ -2754,6 +2832,7 @@ module.exports = function (chai, util) { * @name isNotNumber * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2775,6 +2854,7 @@ module.exports = function (chai, util) { * @name isBoolean * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2796,6 +2876,7 @@ module.exports = function (chai, util) { * @name isNotBoolean * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -2820,6 +2901,7 @@ module.exports = function (chai, util) { * @param {Mixed} value * @param {String} name * @param {String} message + * @namespace Assert * @api public */ @@ -2839,6 +2921,7 @@ module.exports = function (chai, util) { * @param {Mixed} value * @param {String} typeof name * @param {String} message + * @namespace Assert * @api public */ @@ -2860,6 +2943,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {Constructor} constructor * @param {String} message + * @namespace Assert * @api public */ @@ -2881,6 +2965,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {Constructor} constructor * @param {String} message + * @namespace Assert * @api public */ @@ -2901,6 +2986,7 @@ module.exports = function (chai, util) { * @param {Array|String} haystack * @param {Mixed} needle * @param {String} message + * @namespace Assert * @api public */ @@ -2921,6 +3007,7 @@ module.exports = function (chai, util) { * @param {Array|String} haystack * @param {Mixed} needle * @param {String} message + * @namespace Assert * @api public */ @@ -2939,6 +3026,7 @@ module.exports = function (chai, util) { * @param {Mixed} value * @param {RegExp} regexp * @param {String} message + * @namespace Assert * @api public */ @@ -2957,6 +3045,7 @@ module.exports = function (chai, util) { * @param {Mixed} value * @param {RegExp} regexp * @param {String} message + * @namespace Assert * @api public */ @@ -2975,6 +3064,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property * @param {String} message + * @namespace Assert * @api public */ @@ -2993,6 +3083,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property * @param {String} message + * @namespace Assert * @api public */ @@ -3012,6 +3103,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property * @param {String} message + * @namespace Assert * @api public */ @@ -3031,6 +3123,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property * @param {String} message + * @namespace Assert * @api public */ @@ -3051,6 +3144,7 @@ module.exports = function (chai, util) { * @param {String} property * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -3071,6 +3165,7 @@ module.exports = function (chai, util) { * @param {String} property * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -3092,6 +3187,7 @@ module.exports = function (chai, util) { * @param {String} property * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -3113,6 +3209,7 @@ module.exports = function (chai, util) { * @param {String} property * @param {Mixed} value * @param {String} message + * @namespace Assert * @api public */ @@ -3132,6 +3229,7 @@ module.exports = function (chai, util) { * @param {Mixed} object * @param {Number} length * @param {String} message + * @namespace Assert * @api public */ @@ -3160,6 +3258,7 @@ module.exports = function (chai, util) { * @param {RegExp} regexp * @param {String} message * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert * @api public */ @@ -3188,6 +3287,7 @@ module.exports = function (chai, util) { * @param {RegExp} regexp * @param {String} message * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert * @api public */ @@ -3213,6 +3313,7 @@ module.exports = function (chai, util) { * @param {String} operator * @param {Mixed} val2 * @param {String} message + * @namespace Assert * @api public */ @@ -3265,6 +3366,7 @@ module.exports = function (chai, util) { * @param {Number} expected * @param {Number} delta * @param {String} message + * @namespace Assert * @api public */ @@ -3284,6 +3386,7 @@ module.exports = function (chai, util) { * @param {Number} expected * @param {Number} delta * @param {String} message + * @namespace Assert * @api public */ @@ -3303,6 +3406,7 @@ module.exports = function (chai, util) { * @param {Array} set1 * @param {Array} set2 * @param {String} message + * @namespace Assert * @api public */ @@ -3322,6 +3426,7 @@ module.exports = function (chai, util) { * @param {Array} set1 * @param {Array} set2 * @param {String} message + * @namespace Assert * @api public */ @@ -3341,6 +3446,7 @@ module.exports = function (chai, util) { * @param {Array} superset * @param {Array} subset * @param {String} message + * @namespace Assert * @api public */ @@ -3348,6 +3454,27 @@ module.exports = function (chai, util) { new Assertion(superset, msg).to.include.members(subset); } + /** + * ### .includeDeepMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` - using deep equality checking. + * Order is not taken into account. + * Duplicates are ignored. + * + * assert.includeDeepMembers([ {a: 1}, {b: 2}, {c: 3} ], [ {b: 2}, {a: 1}, {b: 2} ], 'include deep members'); + * + * @name includeDeepMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeDeepMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.deep.members(subset); + } + /** * ### .oneOf(inList, list, [message]) * @@ -3359,6 +3486,7 @@ module.exports = function (chai, util) { * @param {*} inList * @param {Array<*>} list * @param {String} message + * @namespace Assert * @api public */ @@ -3380,6 +3508,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3401,6 +3530,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3422,6 +3552,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3443,6 +3574,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3464,6 +3596,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3485,6 +3618,7 @@ module.exports = function (chai, util) { * @param {Object} object * @param {String} property name * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3504,6 +3638,7 @@ module.exports = function (chai, util) { * * @name ifError * @param {Object} object + * @namespace Assert * @api public */ @@ -3524,6 +3659,7 @@ module.exports = function (chai, util) { * @alias extensible * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3548,6 +3684,7 @@ module.exports = function (chai, util) { * @alias notExtensible * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3571,6 +3708,7 @@ module.exports = function (chai, util) { * @alias sealed * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3589,6 +3727,7 @@ module.exports = function (chai, util) { * @alias notSealed * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3609,6 +3748,7 @@ module.exports = function (chai, util) { * @alias frozen * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3627,6 +3767,7 @@ module.exports = function (chai, util) { * @alias notFrozen * @param {Object} object * @param {String} message _optional_ + * @namespace Assert * @api public */ @@ -3676,6 +3817,7 @@ module.exports = function (chai, util) { * @param {Mixed} expected * @param {String} message * @param {String} operator + * @namespace Expect * @api public */ @@ -3740,6 +3882,7 @@ module.exports = function (chai, util) { * @param {Mixed} expected * @param {String} message * @param {String} operator + * @namespace Should * @api public */ @@ -3752,14 +3895,67 @@ module.exports = function (chai, util) { }, should.fail); }; + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * should.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Should + * @api public + */ + should.equal = function (val1, val2, msg) { new Assertion(val1, msg).to.equal(val2); }; + /** + * ### .throw(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * should.throw(fn, 'function throws a reference error'); + * should.throw(fn, /function throws a reference error/); + * should.throw(fn, ReferenceError); + * should.throw(fn, ReferenceError, 'function throws a reference error'); + * should.throw(fn, ReferenceError, /function throws a reference error/); + * + * @name throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Should + * @api public + */ + should.Throw = function (fn, errt, errs, msg) { new Assertion(fn, msg).to.Throw(errt, errs); }; + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi'; + * + * should.exist(foo, 'foo exists'); + * + * @name exist + * @namespace Should + * @api public + */ + should.exist = function (val, msg) { new Assertion(val, msg).to.exist; } @@ -3767,14 +3963,63 @@ module.exports = function (chai, util) { // negation should.not = {} + /** + * ### .not.equal(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * should.not.equal(3, 4, 'these numbers are not equal'); + * + * @name not.equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Should + * @api public + */ + should.not.equal = function (val1, val2, msg) { new Assertion(val1, msg).to.not.equal(val2); }; + /** + * ### .throw(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * should.not.throw(fn, Error, 'function does not throw'); + * + * @name not.throw + * @alias not.Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Should + * @api public + */ + should.not.Throw = function (fn, errt, errs, msg) { new Assertion(fn, msg).to.not.Throw(errt, errs); }; + /** + * ### .not.exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var bar = null; + * + * should.not.exist(bar, 'bar does not exist'); + * + * @name not.exist + * @namespace Should + * @api public + */ + should.not.exist = function (val, msg) { new Assertion(val, msg).to.not.exist; } @@ -3844,6 +4089,7 @@ var call = Function.prototype.call, * @param {String} name of method to add * @param {Function} method function to be used for `name`, when called * @param {Function} chainingBehavior function to be called every time the property is accessed + * @namespace Utils * @name addChainableMethod * @api public */ @@ -3932,6 +4178,7 @@ var config = require('../config'); * @param {Object} ctx object to which the method is added * @param {String} name of method to add * @param {Function} method function to be used for name + * @namespace Utils * @name addMethod * @api public */ @@ -3978,6 +4225,7 @@ var flag = require('./flag'); * @param {Object} ctx object to which the property is added * @param {String} name of property to add * @param {Function} getter function to be used for name + * @namespace Utils * @name addProperty * @api public */ @@ -4012,6 +4260,7 @@ module.exports = function (ctx, name, getter) { * * @param {Mixed} obj constructed Assertion * @param {Array} type A list of allowed types for this assertion + * @namespace Utils * @name expectTypes * @api public */ @@ -4060,6 +4309,7 @@ module.exports = function (obj, types) { * @param {Object} object constructed Assertion * @param {String} key * @param {Mixed} value (optional) + * @namespace Utils * @name flag * @api private */ @@ -4087,6 +4337,8 @@ module.exports = function (obj, key, value) { * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name getActual */ module.exports = function (obj, args) { @@ -4108,6 +4360,7 @@ module.exports = function (obj, args) { * * @param {Object} object * @returns {Array} + * @namespace Utils * @name getEnumerableProperties * @api public */ @@ -4150,6 +4403,7 @@ var flag = require('./flag') * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils * @name getMessage * @api public */ @@ -4165,9 +4419,9 @@ module.exports = function (obj, args) { if(typeof msg === "function") msg = msg(); msg = msg || ''; msg = msg - .replace(/#{this}/g, objDisplay(val)) - .replace(/#{act}/g, objDisplay(actual)) - .replace(/#{exp}/g, objDisplay(expected)); + .replace(/#\{this\}/g, function () { return objDisplay(val); }) + .replace(/#\{act\}/g, function () { return objDisplay(actual); }) + .replace(/#\{exp\}/g, function () { return objDisplay(expected); }); return flagMsg ? flagMsg + ': ' + msg : msg; }; @@ -4185,6 +4439,8 @@ module.exports = function (obj, args) { * Gets the name of a function, in a cross-browser way. * * @param {Function} a function (usually a constructor) + * @namespace Utils + * @name getName */ module.exports = function (func) { @@ -4220,6 +4476,7 @@ var hasProperty = require('./hasProperty'); * @param {String} path * @param {Object} object * @returns {Object} info + * @namespace Utils * @name getPathInfo * @api public */ @@ -4342,13 +4599,14 @@ var getPathInfo = require('./getPathInfo'); * @param {String} path * @param {Object} object * @returns {Object} value or `undefined` + * @namespace Utils * @name getPathValue * @api public */ module.exports = function(path, obj) { var info = getPathInfo(path, obj); return info.value; -}; +}; },{"./getPathInfo":18}],20:[function(require,module,exports){ /*! @@ -4365,6 +4623,7 @@ module.exports = function(path, obj) { * * @param {Object} object * @returns {Array} + * @namespace Utils * @name getProperties * @api public */ @@ -4416,7 +4675,7 @@ var type = require('type-detect'); * hasProperty('str', obj); // true * hasProperty('constructor', obj); // true * hasProperty('bar', obj); // false - * + * * hasProperty('length', obj.str); // true * hasProperty(1, obj.str); // true * hasProperty(5, obj.str); // false @@ -4428,6 +4687,7 @@ var type = require('type-detect'); * @param {Objuect} object * @param {String|Number} name * @returns {Boolean} whether it exists + * @namespace Utils * @name getPathInfo * @api public */ @@ -4604,6 +4864,8 @@ module.exports = inspect; * @param {Number} depth Depth in which to descend in object. Default is 2. * @param {Boolean} colors Flag to turn on ANSI escape codes to color the * output. Default is false (no coloring). + * @namespace Utils + * @name inspect */ function inspect(obj, showHidden, depth, colors) { var ctx = { @@ -4942,6 +5204,7 @@ var config = require('../config'); * * @param {Mixed} javascript object to inspect * @name objDisplay + * @namespace Utils * @api public */ @@ -5005,6 +5268,7 @@ module.exports = function (obj) { * @param {String} name of method / property to overwrite * @param {Function} method function that returns a function to be used for name * @param {Function} chainingBehavior function that returns a function to be used for property + * @namespace Utils * @name overwriteChainableMethod * @api public */ @@ -5061,6 +5325,7 @@ module.exports = function (ctx, name, method, chainingBehavior) { * @param {Object} ctx object whose method is to be overwritten * @param {String} name of method to overwrite * @param {Function} method function that returns a function to be used for name + * @namespace Utils * @name overwriteMethod * @api public */ @@ -5114,6 +5379,7 @@ module.exports = function (ctx, name, method) { * @param {Object} ctx object whose property is to be overwritten * @param {String} name of property to overwrite * @param {Function} getter function that returns a getter function to be used for name + * @namespace Utils * @name overwriteProperty * @api public */ @@ -5154,6 +5420,8 @@ var flag = require('./flag'); * * @param {Object} object (constructed Assertion) * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name test */ module.exports = function (obj, args) { @@ -5187,6 +5455,7 @@ module.exports = function (obj, args) { * @param {Assertion} assertion the assertion to transfer the flags from * @param {Object} object the object to transfer the flags to; usually a new assertion * @param {Boolean} includeAll + * @namespace Utils * @name transferFlags * @api private */ diff --git a/node_modules/es5-shim/es5-shim.js b/node_modules/es5-shim/es5-shim.js index 6022eee8..9a346c34 100644 --- a/node_modules/es5-shim/es5-shim.js +++ b/node_modules/es5-shim/es5-shim.js @@ -328,7 +328,7 @@ var arraySliceApply = apply.bind(array_slice); var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); -var push = call.bind(array_push); +var pushCall = call.bind(array_push); var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); var arraySort = call.bind(ArrayPrototype.sort); @@ -384,18 +384,23 @@ var properlyBoxesContext = function properlyBoxed(method) { // Check node 0.6.21 bug where third parameter is not boxed var properlyBoxesNonStrict = true; var properlyBoxesStrict = true; + var threwException = false; if (method) { - method.call('foo', function (_, __, context) { - if (typeof context !== 'object') { properlyBoxesNonStrict = false; } - }); + try { + method.call('foo', function (_, __, context) { + if (typeof context !== 'object') { properlyBoxesNonStrict = false; } + }); - method.call([1], function () { - 'use strict'; + method.call([1], function () { + 'use strict'; - properlyBoxesStrict = typeof this === 'string'; - }, 'x'); + properlyBoxesStrict = typeof this === 'string'; + }, 'x'); + } catch (e) { + threwException = true; + } } - return !!method && properlyBoxesNonStrict && properlyBoxesStrict; + return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict; }; defineProperties(ArrayPrototype, { @@ -484,7 +489,7 @@ defineProperties(ArrayPrototype, { if (i in self) { value = self[i]; if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { - push(result, value); + pushCall(result, value); } } } @@ -739,7 +744,7 @@ defineProperties(ArrayPrototype, { if (arguments.length > 0 && typeof deleteCount !== 'number') { args = arraySlice(arguments); if (args.length < 2) { - push(args, this.length - start); + pushCall(args, this.length - start); } else { args[1] = ES.ToInteger(deleteCount); } @@ -1027,14 +1032,14 @@ defineProperties($Object, { var skipProto = hasProtoEnumBug && isFn; if ((isStr && hasStringEnumBug) || isArgs) { for (var i = 0; i < object.length; ++i) { - push(theKeys, $String(i)); + pushCall(theKeys, $String(i)); } } if (!isArgs) { for (var name in object) { if (!(skipProto && name === 'prototype') && owns(object, name)) { - push(theKeys, $String(name)); + pushCall(theKeys, $String(name)); } } } @@ -1044,7 +1049,7 @@ defineProperties($Object, { for (var j = 0; j < dontEnumsLength; j++) { var dontEnum = dontEnums[j]; if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { - push(theKeys, dontEnum); + pushCall(theKeys, dontEnum); } } } @@ -1076,6 +1081,190 @@ defineProperties($Object, { // ==== // +var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0; +var aNegativeTestDate = new Date(-1509842289600292); +var aPositiveTestDate = new Date(1449662400000); +var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT'; +var hasToDateStringFormatBug; +var hasToStringFormatBug; +var timeZoneOffset = aNegativeTestDate.getTimezoneOffset(); +if (timeZoneOffset < -720) { + hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875'; + hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString()); +} else { + hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875'; + hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-\+]\d\d\d\d(?: |$)/).test(aPositiveTestDate.toString()); +} + +var originalGetFullYear = call.bind(Date.prototype.getFullYear); +var originalGetMonth = call.bind(Date.prototype.getMonth); +var originalGetDate = call.bind(Date.prototype.getDate); +var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear); +var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth); +var originalGetUTCDate = call.bind(Date.prototype.getUTCDate); +var originalGetUTCDay = call.bind(Date.prototype.getUTCDay); +var originalGetUTCHours = call.bind(Date.prototype.getUTCHours); +var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes); +var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds); +var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds); +var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri']; +var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +var daysInMonth = function daysInMonth(month, year) { + return originalGetDate(new Date(year, month, 0)); +}; + +defineProperties(Date.prototype, { + getFullYear: function getFullYear() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetFullYear(this); + if (year < 0 && originalGetMonth(this) > 11) { + return year + 1; + } + return year; + }, + getMonth: function getMonth() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetFullYear(this); + var month = originalGetMonth(this); + if (year < 0 && month > 11) { + return 0; + } + return month; + }, + getDate: function getDate() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetFullYear(this); + var month = originalGetMonth(this); + var date = originalGetDate(this); + if (year < 0 && month > 11) { + if (month === 12) { + return date; + } + var days = daysInMonth(0, year + 1); + return (days - date) + 1; + } + return date; + }, + getUTCFullYear: function getUTCFullYear() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + if (year < 0 && originalGetUTCMonth(this) > 11) { + return year + 1; + } + return year; + }, + getUTCMonth: function getUTCMonth() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + var month = originalGetUTCMonth(this); + if (year < 0 && month > 11) { + return 0; + } + return month; + }, + getUTCDate: function getUTCDate() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + var month = originalGetUTCMonth(this); + var date = originalGetUTCDate(this); + if (year < 0 && month > 11) { + if (month === 12) { + return date; + } + var days = daysInMonth(0, year + 1); + return (days - date) + 1; + } + return date; + } +}, hasNegativeMonthYearBug); + +defineProperties(Date.prototype, { + toUTCString: function toUTCString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = originalGetUTCDay(this); + var date = originalGetUTCDate(this); + var month = originalGetUTCMonth(this); + var year = originalGetUTCFullYear(this); + var hour = originalGetUTCHours(this); + var minute = originalGetUTCMinutes(this); + var second = originalGetUTCSeconds(this); + return dayName[day] + ', ' + + (date < 10 ? '0' + date : date) + ' ' + + monthName[month] + ' ' + + year + ' ' + + (hour < 10 ? '0' + hour : hour) + ':' + + (minute < 10 ? '0' + minute : minute) + ':' + + (second < 10 ? '0' + second : second) + ' GMT'; + } +}, hasNegativeMonthYearBug || hasToUTCStringFormatBug); + +// Opera 12 has `,` +defineProperties(Date.prototype, { + toDateString: function toDateString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = this.getDay(); + var date = this.getDate(); + var month = this.getMonth(); + var year = this.getFullYear(); + return dayName[day] + ' ' + + monthName[month] + ' ' + + (date < 10 ? '0' + date : date) + ' ' + + year; + } +}, hasNegativeMonthYearBug || hasToDateStringFormatBug); + +// can't use defineProperties here because of toString enumeration issue in IE <= 8 +if (hasNegativeMonthYearBug || hasToStringFormatBug) { + Date.prototype.toString = function toString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = this.getDay(); + var date = this.getDate(); + var month = this.getMonth(); + var year = this.getFullYear(); + var hour = this.getHours(); + var minute = this.getMinutes(); + var second = this.getSeconds(); + var timezoneOffset = this.getTimezoneOffset(); + var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60); + var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60); + return dayName[day] + ' ' + + monthName[month] + ' ' + + (date < 10 ? '0' + date : date) + ' ' + + year + ' ' + + (hour < 10 ? '0' + hour : hour) + ':' + + (minute < 10 ? '0' + minute : minute) + ':' + + (second < 10 ? '0' + second : second) + ' GMT' + + (timezoneOffset > 0 ? '-' : '+') + + (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) + + (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset); + }; + if (supportsDescriptors) { + $Object.defineProperty(Date.prototype, 'toString', { + configurable: true, + enumerable: false, + writable: true + }); + } +} + // ES5 15.9.5.43 // http://es5.github.com/#x15.9.5.43 // This function returns a String value represent the instance in time @@ -1090,39 +1279,33 @@ var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString( defineProperties(Date.prototype, { toISOString: function toISOString() { - var result, length, value, year, month; if (!isFinite(this)) { throw new RangeError('Date.prototype.toISOString called on non-finite value.'); } - year = this.getUTCFullYear(); + var year = originalGetUTCFullYear(this); - month = this.getUTCMonth(); + var month = originalGetUTCMonth(this); // see https://github.com/es-shims/es5-shim/issues/111 year += Math.floor(month / 12); month = (month % 12 + 12) % 12; // the date time string format is specified in 15.9.1.15. - result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; + var result = [month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this)]; year = ( (year < 0 ? '-' : (year > 9999 ? '+' : '')) + strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6) ); - length = result.length; - while (length--) { - value = result[length]; - // pad months, days, hours, minutes, and seconds to have two - // digits. - if (value < 10) { - result[length] = '0' + value; - } + for (var i = 0; i < result.length; ++i) { + // pad months, days, hours, minutes, and seconds to have two digits. + result[i] = strSlice('00' + result[i], -2); } // pad milliseconds to have three digits. return ( year + '-' + arraySlice(result, 0, 2).join('-') + 'T' + arraySlice(result, 2).join(':') + '.' + - strSlice('000' + this.getUTCMilliseconds(), -3) + 'Z' + strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z' ); } }, hasNegativeDateBug || hasSafari51DateBug); @@ -1600,7 +1783,7 @@ if ( // `separatorCopy.lastIndex` is not reliable cross-browser lastIndex = match.index + match[0].length; if (lastIndex > lastLastIndex) { - push(output, strSlice(string, lastLastIndex, match.index)); + pushCall(output, strSlice(string, lastLastIndex, match.index)); // Fix browsers whose `exec` methods don't consistently return `undefined` for // nonparticipating capturing groups if (!compliantExecNpcg && match.length > 1) { @@ -1630,12 +1813,12 @@ if ( } if (lastLastIndex === string.length) { if (lastLength || !separatorCopy.test('')) { - push(output, ''); + pushCall(output, ''); } } else { - push(output, strSlice(string, lastLastIndex)); + pushCall(output, strSlice(string, lastLastIndex)); } - return output.length > splitLimit ? strSlice(output, 0, splitLimit) : output; + return output.length > splitLimit ? arraySlice(output, 0, splitLimit) : output; }; }()); @@ -1656,7 +1839,7 @@ var str_replace = StringPrototype.replace; var replaceReportsGroupsCorrectly = (function () { var groups = []; 'x'.replace(/x(.)?/g, function (match, group) { - push(groups, group); + pushCall(groups, group); }); return groups.length === 1 && typeof groups[0] === 'undefined'; }()); @@ -1674,7 +1857,7 @@ if (!replaceReportsGroupsCorrectly) { searchValue.lastIndex = 0; var args = searchValue.exec(match) || []; searchValue.lastIndex = originalLastIndex; - push(args, arguments[length - 2], arguments[length - 1]); + pushCall(args, arguments[length - 2], arguments[length - 1]); return replaceValue.apply(this, args); }; return str_replace.call(this, searchValue, wrappedReplaceValue); @@ -1719,6 +1902,7 @@ defineProperties(StringPrototype, { return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); } }, hasTrimWhitespaceBug); +var trim = call.bind(String.prototype.trim); var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1; defineProperties(StringPrototype, { @@ -1759,13 +1943,25 @@ if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { parseInt = (function (origParseInt) { var hexRegex = /^[\-+]?0[xX]/; return function parseInt(str, radix) { - var string = $String(str).trim(); + var string = trim(str); var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); return origParseInt(string, defaultedRadix); }; }(parseInt)); } +// https://es5.github.io/#x15.1.2.3 +if (1 / parseFloat('-0') !== -Infinity) { + /* global parseFloat: true */ + parseFloat = (function (origParseFloat) { + return function parseFloat(string) { + var inputString = trim(string); + var result = origParseFloat(inputString); + return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result; + }; + }(parseFloat)); +} + if (String(new RangeError('test')) !== 'RangeError: test') { var errorToStringShim = function toString() { if (typeof this === 'undefined' || this === null) { diff --git a/node_modules/mocha/mocha.js b/node_modules/mocha/mocha.js index 84c384bd..19561978 100644 --- a/node_modules/mocha/mocha.js +++ b/node_modules/mocha/mocha.js @@ -419,6 +419,21 @@ Context.prototype.skip = function() { return this; }; +/** + * Allow a number of retries on failed tests + * + * @api private + * @param {number} n + * @return {Context} self + */ +Context.prototype.retries = function(n) { + if (!arguments.length) { + return this.runnable().retries(); + } + this.runnable().retries(n); + return this; +}; + /** * Inspect the context void of `._runnable`. * @@ -559,7 +574,7 @@ module.exports = function(suite) { * acting as a thunk. */ - context.it = context.specify = function(title, fn) { + var it = context.it = context.specify = function(title, fn) { var suite = suites[0]; if (suite.pending) { fn = null; @@ -575,7 +590,7 @@ module.exports = function(suite) { */ context.it.only = function(title, fn) { - var test = context.it(title, fn); + var test = it(title, fn); var reString = '^' + escapeRe(test.fullTitle()) + '$'; mocha.grep(new RegExp(reString)); return test; @@ -588,6 +603,13 @@ module.exports = function(suite) { context.xit = context.xspecify = context.it.skip = function(title) { context.it(title); }; + + /** + * Number of attempts to retry. + */ + context.it.retries = function(n) { + context.retries(n); + }; }); }; @@ -664,6 +686,15 @@ module.exports = function(suites, context) { */ skip: function(title) { context.test(title); + }, + + /** + * Number of retry attempts + * + * @param {string} n + */ + retries: function(n) { + context.retries(n); } } }; @@ -725,7 +756,7 @@ module.exports = function(suite) { } else { suite = Suite.create(suites[0], key); suites.unshift(suite); - visit(obj[key]); + visit(obj[key], file); suites.shift(); } } @@ -830,6 +861,7 @@ module.exports = function(suite) { }; context.test.skip = common.test.skip; + context.test.retries = common.test.retries; }); }; @@ -937,6 +969,7 @@ module.exports = function(suite) { }; context.test.skip = common.test.skip; + context.test.retries = common.test.retries; }); }; @@ -1006,6 +1039,7 @@ function image(name) { * - `reporter` reporter instance, defaults to `mocha.reporters.spec` * - `globals` array of accepted globals * - `timeout` timeout in milliseconds + * - `retries` number of times to retry failed tests * - `bail` bail on the first test failure * - `slow` milliseconds to wait before considering a test slow * - `ignoreLeaks` ignore global leaks @@ -1032,6 +1066,9 @@ function Mocha(options) { if (typeof options.timeout !== 'undefined' && options.timeout !== null) { this.timeout(options.timeout); } + if (typeof options.retries !== 'undefined' && options.retries !== null) { + this.retries(options.retries); + } this.useColors(options.useColors); if (options.enableTimeouts !== null) { this.enableTimeouts(options.enableTimeouts); @@ -1153,14 +1190,13 @@ Mocha.prototype.ui = function(name) { Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; - var pending = this.files.length; this.files.forEach(function(file) { file = path.resolve(file); suite.emit('pre-require', global, file, self); suite.emit('require', require(file), file, self); suite.emit('post-require', global, file, self); - --pending || (fn && fn()); }); + fn && fn(); }; /** @@ -1316,6 +1352,18 @@ Mocha.prototype.timeout = function(timeout) { return this; }; +/** + * Set the number of times to retry failed tests. + * + * @param {Number} retry times + * @return {Mocha} + * @api public + */ +Mocha.prototype.retries = function(n) { + this.suite.retries(n); + return this; +}; + /** * Set slowness threshold in milliseconds. * @@ -2121,13 +2169,13 @@ function Doc(runner) { runner.on('pass', function(test) { console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); + var code = utils.escape(utils.clean(test.body)); console.log('%s
%s
', indent(), code); }); runner.on('fail', function(test, err) { console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); + var code = utils.escape(utils.clean(test.fn.body)); console.log('%s
%s
', indent(), code); console.log('%s
%s
', indent(), utils.escape(err)); }); @@ -2396,7 +2444,10 @@ function HTML(runner) { }); runner.on('fail', function(test) { - if (test.type === 'hook') { + // For type = 'test' its possible that the test failed due to multiple + // done() calls. So report the issue here. + if (test.type === 'hook' + || test.type === 'test') { runner.emit('test end', test); } }); @@ -2464,7 +2515,7 @@ function HTML(runner) { pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; }); - var pre = fragment('
%e
', utils.clean(test.fn.toString())); + var pre = fragment('
%e
', utils.clean(test.body)); el.appendChild(pre); pre.style.display = 'none'; } @@ -2762,6 +2813,7 @@ function coverage(filename, data) { function clean(test) { return { duration: test.duration, + currentRetry: test.currentRetry(), fullTitle: test.fullTitle(), title: test.title }; @@ -2826,7 +2878,8 @@ function clean(test) { return { title: test.title, fullTitle: test.fullTitle(), - duration: test.duration + duration: test.duration, + currentRetry: test.currentRetry() }; } @@ -2904,6 +2957,7 @@ function clean(test) { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, + currentRetry: test.currentRetry(), err: errorJSON(test.err || {}) }; } @@ -3171,7 +3225,7 @@ function Markdown(runner) { }); runner.on('pass', function(test) { - var code = utils.clean(test.fn.toString()); + var code = utils.clean(test.body); buf += test.title + '.\n'; buf += '\n```js\n'; buf += code + '\n'; @@ -3740,7 +3794,7 @@ function title(test) { } },{"./base":17}],34:[function(require,module,exports){ -(function (global){ +(function (process,global){ /** * Module dependencies. */ @@ -3750,6 +3804,8 @@ var utils = require('../utils'); var inherits = utils.inherits; var fs = require('fs'); var escape = utils.escape; +var mkdirp = require('mkdirp'); +var path = require('path'); /** * Save timer references to avoid Sinon interfering (see GH-237). @@ -3786,6 +3842,7 @@ function XUnit(runner, options) { if (!fs.createWriteStream) { throw new Error('file output not supported in browser'); } + mkdirp.sync(path.dirname(options.reporterOptions.output)); self.fileStream = fs.createWriteStream(options.reporterOptions.output); } @@ -3849,6 +3906,8 @@ XUnit.prototype.done = function(failures, fn) { XUnit.prototype.write = function(line) { if (this.fileStream) { this.fileStream.write(line + '\n'); + } else if (typeof process === 'object' && process.stdout) { + process.stdout.write(line + '\n'); } else { console.log(line); } @@ -3911,8 +3970,8 @@ function cdata(str) { return ''; } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../utils":39,"./base":17,"fs":41}],35:[function(require,module,exports){ +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils":39,"./base":17,"_process":51,"fs":41,"mkdirp":70,"path":41}],35:[function(require,module,exports){ (function (global){ /** * Module dependencies. @@ -3968,6 +4027,8 @@ function Runnable(title, fn) { this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); + this._retries = -1; + this._currentRetry = 0; } /** @@ -4044,6 +4105,30 @@ Runnable.prototype.skip = function() { throw new Pending(); }; +/** + * Set number of retries. + * + * @api private + */ +Runnable.prototype.retries = function(n) { + if (!arguments.length) { + return this._retries; + } + this._retries = n; +}; + +/** + * Get current retry + * + * @api private + */ +Runnable.prototype.currentRetry = function(n) { + if (!arguments.length) { + return this._currentRetry; + } + this._currentRetry = n; +}; + /** * Return the full title generated by recursively concatenating the parent's * full title. @@ -4114,6 +4199,9 @@ Runnable.prototype.resetTimeout = function() { * @param {string[]} globals */ Runnable.prototype.globals = function(globals) { + if (!arguments.length) { + return this._allowedGlobals; + } this._allowedGlobals = globals; }; @@ -4205,6 +4293,9 @@ Runnable.prototype.run = function(fn) { result .then(function() { done(); + // Return null so libraries like bluebird do not warn about + // subsequently constructed Promises. + return null; }, function(reason) { done(reason || new Error('Promise rejected with no or falsy reason')); @@ -4255,6 +4346,7 @@ var stackFilter = utils.stackTraceFilter(); var stringify = utils.stringify; var type = utils.type; var undefinedError = utils.undefinedError; +var isArray = utils.isArray; /** * Non-enumerable globals. @@ -4746,8 +4838,12 @@ Runner.prototype.runTests = function(suite, fn) { return; } + function parentPending(suite) { + return suite.pending || (suite.parent && parentPending(suite.parent)); + } + // pending - if (test.pending) { + if (test.pending || parentPending(test.parent)) { self.emit('pending', test); self.emit('test end', test); return next(); @@ -4767,10 +4863,19 @@ Runner.prototype.runTests = function(suite, fn) { self.currentRunnable = self.test; self.runTest(function(err) { test = self.test; - if (err) { + var retry = test.currentRetry(); if (err instanceof Pending) { + test.pending = true; self.emit('pending', test); + } else if (retry < test.retries()) { + var clonedTest = test.clone(); + clonedTest.currentRetry(retry + 1); + tests.unshift(clonedTest); + + // Early return + hook trigger so that it doesn't + // increment the count wrong + return self.hookUp('afterEach', next); } else { self.fail(test, err); } @@ -4861,6 +4966,10 @@ Runner.prototype.runSuite = function(suite, fn) { // mark that the afterAll block has been called once // and so can be skipped if there is an error in it. afterAllHookCalled = true; + + // remove reference to test + delete self.test; + self.hook('afterAll', function() { self.emit('suite end', suite); fn(errSuite); @@ -4947,6 +5056,44 @@ Runner.prototype.uncaught = function(err) { this.emit('end'); }; +/** + * Cleans up the references to all the deferred functions + * (before/after/beforeEach/afterEach) and tests of a Suite. + * These must be deleted otherwise a memory leak can happen, + * as those functions may reference variables from closures, + * thus those variables can never be garbage collected as long + * as the deferred functions exist. + * + * @param {Suite} suite + */ +function cleanSuiteReferences(suite) { + function cleanArrReferences(arr) { + for (var i = 0; i < arr.length; i++) { + delete arr[i].fn; + } + } + + if (isArray(suite._beforeAll)) { + cleanArrReferences(suite._beforeAll); + } + + if (isArray(suite._beforeEach)) { + cleanArrReferences(suite._beforeEach); + } + + if (isArray(suite._afterAll)) { + cleanArrReferences(suite._afterAll); + } + + if (isArray(suite._afterEach)) { + cleanArrReferences(suite._afterEach); + } + + for (var i = 0; i < suite.tests.length; i++) { + delete suite.tests[i].fn; + } +} + /** * Run the root suite and invoke `fn(failures)` * on completion. @@ -4978,6 +5125,9 @@ Runner.prototype.run = function(fn) { debug('start'); + // references cleanup to avoid memory leaks + this.on('suite end', cleanSuiteReferences); + // callback this.on('end', function() { debug('end'); @@ -5143,6 +5293,7 @@ function Suite(title, parentContext) { this._enableTimeouts = true; this._slow = 75; this._bail = false; + this._retries = -1; this.delayed = false; } @@ -5162,6 +5313,7 @@ Suite.prototype.clone = function() { debug('clone'); suite.ctx = this.ctx; suite.timeout(this.timeout()); + suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); @@ -5190,6 +5342,22 @@ Suite.prototype.timeout = function(ms) { return this; }; +/** + * Set number of times to retry a failed test. + * + * @api private + * @param {number|string} n + * @return {Suite|number} for chaining + */ +Suite.prototype.retries = function(n) { + if (!arguments.length) { + return this._retries; + } + debug('retries %d', n); + this._retries = parseInt(n, 10) || 0; + return this; +}; + /** * Set timeout to `enabled`. * @@ -5262,6 +5430,7 @@ Suite.prototype.beforeAll = function(title, fn) { var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); + hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; @@ -5291,6 +5460,7 @@ Suite.prototype.afterAll = function(title, fn) { var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); + hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; @@ -5320,6 +5490,7 @@ Suite.prototype.beforeEach = function(title, fn) { var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); + hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; @@ -5349,6 +5520,7 @@ Suite.prototype.afterEach = function(title, fn) { var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); + hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; @@ -5367,6 +5539,7 @@ Suite.prototype.afterEach = function(title, fn) { Suite.prototype.addSuite = function(suite) { suite.parent = this; suite.timeout(this.timeout()); + suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); @@ -5385,6 +5558,7 @@ Suite.prototype.addSuite = function(suite) { Suite.prototype.addTest = function(test) { test.parent = this; test.timeout(this.timeout()); + test.retries(this.retries()); test.enableTimeouts(this.enableTimeouts()); test.slow(this.slow()); test.ctx = this.ctx; @@ -5472,6 +5646,7 @@ function Test(title, fn) { Runnable.call(this, title, fn); this.pending = !fn; this.type = 'test'; + this.body = (fn || '').toString(); } /** @@ -5479,6 +5654,20 @@ function Test(title, fn) { */ inherits(Test, Runnable); +Test.prototype.clone = function() { + var test = new Test(this.title, this.fn); + test.timeout(this.timeout()); + test.slow(this.slow()); + test.enableTimeouts(this.enableTimeouts()); + test.retries(this.retries()); + test.currentRetry(this.currentRetry()); + test.globals(this.globals()); + test.parent = this.parent; + test.file = this.file; + test.ctx = this.ctx; + return test; +}; + },{"./runnable":35,"./utils":39}],39:[function(require,module,exports){ (function (process,Buffer){ /* eslint-env browser */ @@ -5670,6 +5859,8 @@ var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj return Object.prototype.toString.call(obj) === '[object Array]'; }; +exports.isArray = isArray; + /** * Buffer.prototype.toJSON polyfill. * @@ -5744,7 +5935,7 @@ exports.slug = function(str) { exports.clean = function(str) { str = str .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') - .replace(/^function *\(.*\)\s*{|\(.*\) *=> *{?/, '') + .replace(/^function *\(.*\)\s*\{|\(.*\) *=> *\{?/, '') .replace(/\s+\}$/, ''); var spaces = str.match(/^\n?( *)/)[1].length; @@ -6081,7 +6272,7 @@ exports.canonicalize = function(value, stack) { canonicalizedObj = value; break; default: - canonicalizedObj = value.toString(); + canonicalizedObj = value + ''; } return canonicalizedObj; @@ -12250,6 +12441,108 @@ function growl(msg, options, fn) { }).call(this,require('_process')) },{"_process":51,"child_process":41,"fs":41,"os":50,"path":41}],70:[function(require,module,exports){ +(function (process){ +var path = require('path'); +var fs = require('fs'); +var _0777 = parseInt('0777', 8); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, opts, f, made) { + if (typeof opts === 'function') { + f = opts; + opts = {}; + } + else if (!opts || typeof opts !== 'object') { + opts = { mode: opts }; + } + + var mode = opts.mode; + var xfs = opts.fs || fs; + + if (mode === undefined) { + mode = _0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + p = path.resolve(p); + + xfs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), opts, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, opts, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + xfs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, opts, made) { + if (!opts || typeof opts !== 'object') { + opts = { mode: opts }; + } + + var mode = opts.mode; + var xfs = opts.fs || fs; + + if (mode === undefined) { + mode = _0777 & (~process.umask()); + } + if (!made) made = null; + + p = path.resolve(p); + + try { + xfs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), opts, made); + sync(p, opts, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = xfs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; + +}).call(this,require('_process')) +},{"_process":51,"fs":41,"path":41}],71:[function(require,module,exports){ (function (process,global){ /** * Shim process.stdout. @@ -12410,8 +12703,8 @@ Mocha.process = process; * Expose mocha. */ -window.Mocha = Mocha; -window.mocha = mocha; +global.Mocha = Mocha; +global.mocha = mocha; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../":1,"_process":51,"browser-stdout":40}]},{},[70]); +},{"../":1,"_process":51,"browser-stdout":40}]},{},[71]); diff --git a/package.json b/package.json index 50f064ad..c601a532 100644 --- a/package.json +++ b/package.json @@ -67,17 +67,17 @@ }, "dependencies": {}, "devDependencies": { - "chai": "^3.4.1", - "es5-shim": "^4.4.1", + "chai": "^3.5.0", + "es5-shim": "^4.5.2", "eslint": "^1.10.3", "@ljharb/eslint-config": "^1.6.1", "grunt": "^0.4.5", "grunt-contrib-connect": "^0.11.2", "grunt-contrib-watch": "^0.6.1", "grunt-saucelabs": "^8.6.2", - "jscs": "^2.8.0", + "jscs": "^2.9.0", "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "promises-aplus-tests": "^2.1.1", "promises-es6-tests": "^0.5.0", "uglify-js": "^2.6.1",