-
-
Notifications
You must be signed in to change notification settings - Fork 693
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(utils): add length guard to methods
When the `length` assertion is chained directly off of an uninvoked method, it references `function`'s built-in `length` property instead of Chai's `length` assertion. This commit adds a guard to Chai methods to detect this problem and throw a helpful error message that advises the user on how to correct it.
- Loading branch information
Showing
8 changed files
with
397 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
var config = require('../config'); | ||
|
||
var fnDesc = Object.getOwnPropertyDescriptor(function () {}, 'length'); | ||
var isFnLengthConfigurable = typeof fnDesc === 'object' | ||
? fnDesc.configurable | ||
: false; | ||
|
||
/*! | ||
* Chai - addLengthGuard utility | ||
* Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com> | ||
* MIT Licensed | ||
*/ | ||
|
||
/** | ||
* # addLengthGuard(fn, assertionName, isChainable) | ||
* | ||
* Define `length` as a getter on the given uninvoked method assertion. The | ||
* getter acts as a guard against chaining `length` directly off of an uninvoked | ||
* method assertion, which is a problem because it references `function`'s | ||
* built-in `length` property instead of Chai's `length` assertion. When the | ||
* getter catches the user making this mistake, it throws an error with a | ||
* helpful message. | ||
* | ||
* There are two ways in which this mistake can be made. The first way is by | ||
* chaining the `length` assertion directly off of an uninvoked chainable | ||
* method. In this case, Chai suggests that the user use `lengthOf` instead. The | ||
* second way is by chaining the `length` assertion directly off of an uninvoked | ||
* non-chainable method. Non-chainable methods must be invoked prior to | ||
* chaining. In this case, Chai suggests that the user consult the docs for the | ||
* given assertion. | ||
* | ||
* If the `length` property of functions is unconfigurable, then return `fn` | ||
* without modification. | ||
* | ||
* Note that in ES6, the function's `length` property is configurable, so once | ||
* support for legacy environments is dropped, Chai's `length` property can | ||
* replace the built-in function's `length` property, and this length guard will | ||
* no longer be necessary. In the mean time, maintaining consistency across all | ||
* environments is the priority. | ||
* | ||
* @param {Function} fn | ||
* @param {String} assertionName | ||
* @param {Boolean} isChainable | ||
* @namespace Utils | ||
* @name addLengthGuard | ||
*/ | ||
|
||
module.exports = function addLengthGuard (fn, assertionName, isChainable) { | ||
if (isFnLengthConfigurable !== true) return fn; | ||
|
||
Object.defineProperty(fn, 'length', { | ||
get: function () { | ||
if (isChainable === true) { | ||
throw Error('Invalid Chai property: ' + assertionName + '.length. Due' + | ||
' to a compatibility issue, "length" cannot directly follow "' + | ||
assertionName + '". Use "' + assertionName + '.lengthOf" instead.'); | ||
} | ||
|
||
throw Error('Invalid Chai property: ' + assertionName + '.length. See' + | ||
' docs for proper usage of "' + assertionName + '".'); | ||
} | ||
}); | ||
|
||
return fn; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.