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
%s
%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",