Skip to content

Commit

Permalink
feat: Add the .fail([message]) interface
Browse files Browse the repository at this point in the history
Fix chaijs#1116.
The `assert.fail` interface should accept being called with
only 1 arguments to fail with a custom message.
  • Loading branch information
s-leroux committed Jan 11, 2018
1 parent f54f71c commit bde6607
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 45 deletions.
108 changes: 73 additions & 35 deletions chai.js
Expand Up @@ -355,7 +355,7 @@ module.exports = {
* @api public
*/

proxyExcludedKeys: ['then', 'inspect', 'toJSON']
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON']
};

},{}],5:[function(require,module,exports){
Expand Down Expand Up @@ -571,7 +571,6 @@ module.exports = function (chai, _) {
flag(this, 'all', false);
});


/**
* ### .all
*
Expand Down Expand Up @@ -950,9 +949,9 @@ module.exports = function (chai, _) {
/**
* ### .ok
*
* Asserts that the target is loosely (`==`) equal to `true`. However, it's
* often best to assert that the target is strictly (`===`) or deeply equal to
* its expected value.
* Asserts that the target is a truthy value (considered `true` in boolean context).
* However, it's often best to assert that the target is strictly (`===`) or
* deeply equal to its expected value.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.be.ok; // Not recommended
Expand Down Expand Up @@ -1503,6 +1502,7 @@ module.exports = function (chai, _) {
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, errorMessage
, shouldThrow = true;

if (doLength) {
Expand Down Expand Up @@ -1599,6 +1599,7 @@ module.exports = function (chai, _) {
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, errorMessage
, shouldThrow = true;

if (doLength) {
Expand Down Expand Up @@ -1694,6 +1695,7 @@ module.exports = function (chai, _) {
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, errorMessage
, shouldThrow = true;

if (doLength) {
Expand Down Expand Up @@ -1789,6 +1791,7 @@ module.exports = function (chai, _) {
, ssfi = flag(this, 'ssfi')
, objType = _.type(obj).toLowerCase()
, nType = _.type(n).toLowerCase()
, errorMessage
, shouldThrow = true;

if (doLength) {
Expand Down Expand Up @@ -1885,6 +1888,7 @@ module.exports = function (chai, _) {
, objType = _.type(obj).toLowerCase()
, startType = _.type(start).toLowerCase()
, finishType = _.type(finish).toLowerCase()
, errorMessage
, shouldThrow = true
, range = (startType === 'date' && finishType === 'date')
? start.toUTCString() + '..' + finish.toUTCString()
Expand Down Expand Up @@ -2119,10 +2123,30 @@ module.exports = function (chai, _) {
, isOwn = flag(this, 'own')
, flagMsg = flag(this, 'message')
, obj = flag(this, 'object')
, ssfi = flag(this, 'ssfi');
, ssfi = flag(this, 'ssfi')
, nameType = typeof name;

flagMsg = flagMsg ? flagMsg + ': ' : '';

if (isNested) {
if (nameType !== 'string') {
throw new AssertionError(
flagMsg + 'the argument to property must be a string when using nested syntax',
undefined,
ssfi
);
}
} else {
if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {
throw new AssertionError(
flagMsg + 'the argument to property must be a string, number, or symbol',
undefined,
ssfi
);
}
}

if (isNested && isOwn) {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'The "nested" and "own" flags cannot be combined.',
undefined,
Expand All @@ -2131,7 +2155,6 @@ module.exports = function (chai, _) {
}

if (obj === null || obj === undefined) {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'Target cannot be null or undefined.',
undefined,
Expand Down Expand Up @@ -2610,6 +2633,7 @@ module.exports = function (chai, _) {
, isDeep = flag(this, 'deep')
, str
, deepStr = ''
, actual
, ok = true
, flagMsg = flag(this, 'message');

Expand All @@ -2626,7 +2650,6 @@ module.exports = function (chai, _) {
if (keysType !== 'Array') {
keys = Array.prototype.slice.call(arguments);
}

} else {
actual = _.getOwnEnumerableProperties(obj);

Expand Down Expand Up @@ -2659,8 +2682,7 @@ module.exports = function (chai, _) {
var len = keys.length
, any = flag(this, 'any')
, all = flag(this, 'all')
, expected = keys
, actual;
, expected = keys;

if (!any && !all) {
all = true;
Expand Down Expand Up @@ -3362,7 +3384,7 @@ module.exports = function (chai, _) {
var contains = flag(this, 'contains');
var ordered = flag(this, 'ordered');

var subject, failMsg, failNegateMsg, lengthCheck;
var subject, failMsg, failNegateMsg;

if (contains) {
subject = ordered ? 'an ordered superset' : 'a superset';
Expand Down Expand Up @@ -3434,7 +3456,6 @@ module.exports = function (chai, _) {

Assertion.addMethod('oneOf', oneOf);


/**
* ### .change(subject[, prop[, msg]])
*
Expand Down Expand Up @@ -4082,7 +4103,7 @@ module.exports = function (chai, _) {
var obj = flag(this, 'object');

this.assert(
typeof obj === "number" && isFinite(obj)
typeof obj === 'number' && isFinite(obj)
, 'expected #{this} to be a finite number'
, 'expected #{this} to not be a finite number'
);
Expand All @@ -4096,9 +4117,7 @@ module.exports = function (chai, _) {
* MIT Licensed
*/


module.exports = function (chai, util) {

/*!
* Chai dependencies.
*/
Expand Down Expand Up @@ -4135,10 +4154,18 @@ module.exports = function (chai, util) {
};

/**
* ### .fail([message])
* ### .fail(actual, expected, [message], [operator])
*
* Throw a failure. Node.js `assert` module-compatible.
*
* assert.fail();
* assert.fail("custom error message");
* assert.fail(1, 2);
* assert.fail(1, 2, "custom error message");
* assert.fail(1, 2, "custom error message", ">");
* assert.fail(1, 2, undefined, ">");
*
* @name fail
* @param {Mixed} actual
* @param {Mixed} expected
Expand All @@ -4149,6 +4176,13 @@ module.exports = function (chai, util) {
*/

assert.fail = function (actual, expected, message, operator) {
if (arguments.length < 2) {
// Comply with Node's fail([message]) interface

message = actual;
actual = undefined;
}

message = message || 'assert.fail()';
throw new chai.AssertionError(message, {
actual: actual
Expand Down Expand Up @@ -6034,8 +6068,8 @@ module.exports = function (chai, util) {
* If `errMsgMatcher` is provided, it also asserts that the error thrown will have a
* message matching `errMsgMatcher`.
*
* assert.throws(fn, 'function throws a reference error');
* assert.throws(fn, /function throws a reference error/);
* assert.throws(fn, 'Error thrown must have this msg');
* assert.throws(fn, /Error thrown must have a msg that matches this/);
* assert.throws(fn, ReferenceError);
* assert.throws(fn, errorInstance);
* assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg');
Expand Down Expand Up @@ -7202,6 +7236,7 @@ module.exports = function (chai, util) {
};

/**
* ### .fail([message])
* ### .fail(actual, expected, [message], [operator])
*
* Throw a failure.
Expand All @@ -7216,6 +7251,11 @@ module.exports = function (chai, util) {
*/

chai.expect.fail = function (actual, expected, message, operator) {
if (arguments.length < 2) {
message = actual;
actual = undefined;
}

message = message || 'expect.fail()';
throw new chai.AssertionError(message, {
actual: actual
Expand Down Expand Up @@ -7270,6 +7310,7 @@ module.exports = function (chai, util) {
var should = {};

/**
* ### .fail([message])
* ### .fail(actual, expected, [message], [operator])
*
* Throw a failure.
Expand All @@ -7284,6 +7325,11 @@ module.exports = function (chai, util) {
*/

should.fail = function (actual, expected, message, operator) {
if (arguments.length < 2) {
message = actual;
actual = undefined;
}

message = message || 'should.fail()';
throw new chai.AssertionError(message, {
actual: actual
Expand Down Expand Up @@ -7586,8 +7632,6 @@ module.exports = function addChainableMethod(ctx, name, method, chainingBehavior
};

},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],10:[function(require,module,exports){
var config = require('../config');

var fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length');

/*!
Expand Down Expand Up @@ -7649,7 +7693,7 @@ module.exports = function addLengthGuard (fn, assertionName, isChainable) {
return fn;
};

},{"../config":4}],11:[function(require,module,exports){
},{}],11:[function(require,module,exports){
/*!
* Chai - addMethod utility
* Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
Expand Down Expand Up @@ -7977,7 +8021,6 @@ module.exports = function getEnumerableProperties(object) {

var flag = require('./flag')
, getActual = require('./getActual')
, inspect = require('./inspect')
, objDisplay = require('./objDisplay');

/**
Expand Down Expand Up @@ -8017,7 +8060,7 @@ module.exports = function getMessage(obj, args) {
return flagMsg ? flagMsg + ': ' + msg : msg;
};

},{"./flag":15,"./getActual":16,"./inspect":23,"./objDisplay":26}],19:[function(require,module,exports){
},{"./flag":15,"./getActual":16,"./objDisplay":26}],19:[function(require,module,exports){
/*!
* Chai - getOwnEnumerableProperties utility
* Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>
Expand Down Expand Up @@ -8488,7 +8531,6 @@ function formatValue(ctx, value, recurseTimes) {
return reduceToSingleString(output, base, braces);
}


function formatPrimitive(ctx, value) {
switch (typeof value) {
case 'undefined':
Expand Down Expand Up @@ -8518,12 +8560,10 @@ function formatPrimitive(ctx, value) {
}
}


function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}


function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
Expand Down Expand Up @@ -8626,12 +8666,8 @@ function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
return name + ': ' + str;
}


function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.length + 1;
}, 0);

Expand Down Expand Up @@ -9154,10 +9190,12 @@ function stringDistance(strA, strB, memo) {
if (strA.length === 0 || strB.length === 0) {
memo[strA.length][strB.length] = Math.max(strA.length, strB.length);
} else {
var sliceA = strA.slice(0, -1);
var sliceB = strB.slice(0, -1);
memo[strA.length][strB.length] = Math.min(
stringDistance(strA.slice(0, -1), strB, memo) + 1,
stringDistance(strA, strB.slice(0, -1), memo) + 1,
stringDistance(strA.slice(0, -1), strB.slice(0, -1), memo) +
stringDistance(sliceA, strB, memo) + 1,
stringDistance(strA, sliceB, memo) + 1,
stringDistance(sliceA, sliceB, memo) +
(strA.slice(-1) === strB.slice(-1) ? 0 : 1)
);
}
Expand Down Expand Up @@ -9554,7 +9592,7 @@ FakeMap.prototype = {
return key[this._key];
},
set: function setMap(key, value) {
if (!Object.isFrozen(key)) {
if (Object.isExtensible(key)) {
Object.defineProperty(key, this._key, {
value: value,
configurable: true,
Expand Down Expand Up @@ -10704,4 +10742,4 @@ module.exports = function typeDetect(obj) {
module.exports.typeDetect = module.exports;

},{}]},{},[1])(1)
});
});
15 changes: 15 additions & 0 deletions lib/chai/interface/assert.js
Expand Up @@ -41,10 +41,18 @@ module.exports = function (chai, util) {
};

/**
* ### .fail([message])
* ### .fail(actual, expected, [message], [operator])
*
* Throw a failure. Node.js `assert` module-compatible.
*
* assert.fail();
* assert.fail("custom error message");
* assert.fail(1, 2);
* assert.fail(1, 2, "custom error message");
* assert.fail(1, 2, "custom error message", ">");
* assert.fail(1, 2, undefined, ">");
*
* @name fail
* @param {Mixed} actual
* @param {Mixed} expected
Expand All @@ -55,6 +63,13 @@ module.exports = function (chai, util) {
*/

assert.fail = function (actual, expected, message, operator) {
if (arguments.length < 2) {
// Comply with Node's fail([message]) interface

message = actual;
actual = undefined;
}

message = message || 'assert.fail()';
throw new chai.AssertionError(message, {
actual: actual
Expand Down

0 comments on commit bde6607

Please sign in to comment.