mirror of
https://github.com/chaijs/chai
synced 2024-11-15 00:07:11 +00:00
util: add overwriteChainableMethod utility (for #215)
This commit is contained in:
parent
4ce3d420e2
commit
2127525933
6 changed files with 136 additions and 4 deletions
|
@ -35,6 +35,7 @@
|
|||
, "lib/chai/utils/objDisplay.js"
|
||||
, "lib/chai/utils/overwriteMethod.js"
|
||||
, "lib/chai/utils/overwriteProperty.js"
|
||||
, "lib/chai/utils/overwriteChainableMethod.js"
|
||||
, "lib/chai/utils/test.js"
|
||||
, "lib/chai/utils/transferFlags.js"
|
||||
, "lib/chai/utils/type.js"
|
||||
|
|
|
@ -81,6 +81,10 @@ module.exports = function (_chai, util) {
|
|||
util.overwriteMethod(this.prototype, name, fn);
|
||||
};
|
||||
|
||||
Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) {
|
||||
util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior);
|
||||
};
|
||||
|
||||
/*!
|
||||
* ### .assert(expression, message, negateMessage, expected, actual)
|
||||
*
|
||||
|
|
|
@ -54,16 +54,28 @@ var call = Function.prototype.call,
|
|||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function (ctx, name, method, chainingBehavior) {
|
||||
module.exports = addChainableMethod = function (ctx, name, method, chainingBehavior) {
|
||||
if (typeof chainingBehavior !== 'function')
|
||||
chainingBehavior = function () { };
|
||||
|
||||
var chainableBehavior = {
|
||||
ctx: ctx,
|
||||
method: method,
|
||||
chainingBehavior: chainingBehavior
|
||||
};
|
||||
|
||||
// save the methods so we can overwrite them later, if we need to.
|
||||
if (!addChainableMethod.methods[name])
|
||||
addChainableMethod.methods[name] = [];
|
||||
|
||||
addChainableMethod.methods[name].push(chainableBehavior);
|
||||
|
||||
Object.defineProperty(ctx, name,
|
||||
{ get: function () {
|
||||
chainingBehavior.call(this);
|
||||
chainableBehavior.chainingBehavior.call(this);
|
||||
|
||||
var assert = function () {
|
||||
var result = method.apply(this, arguments);
|
||||
var result = chainableBehavior.method.apply(this, arguments);
|
||||
return result === undefined ? this : result;
|
||||
};
|
||||
|
||||
|
@ -92,3 +104,5 @@ module.exports = function (ctx, name, method, chainingBehavior) {
|
|||
, configurable: true
|
||||
});
|
||||
};
|
||||
|
||||
addChainableMethod.methods = {};
|
||||
|
|
|
@ -106,3 +106,9 @@ exports.overwriteMethod = require('./overwriteMethod');
|
|||
|
||||
exports.addChainableMethod = require('./addChainableMethod');
|
||||
|
||||
/*!
|
||||
* Overwrite chainable method
|
||||
*/
|
||||
|
||||
exports.overwriteChainableMethod = require('./overwriteChainableMethod');
|
||||
|
||||
|
|
65
lib/chai/utils/overwriteChainableMethod.js
Normal file
65
lib/chai/utils/overwriteChainableMethod.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*!
|
||||
* Chai - overwriteChainableMethod utility
|
||||
* Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var addChainableMethod = require('./addChainableMethod');
|
||||
|
||||
/**
|
||||
* ### overwriteChainableMethod (ctx, name, fn)
|
||||
*
|
||||
* Overwites an already existing chainable method
|
||||
* and provides access to the previous function or
|
||||
* property. Must return functions to be used for
|
||||
* name.
|
||||
*
|
||||
* utils.overwriteChainableMethod(chai.Assertion.prototype, 'length',
|
||||
* function (_super) {
|
||||
* }
|
||||
* , function (_super) {
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* Can also be accessed directly from `chai.Assertion`.
|
||||
*
|
||||
* chai.Assertion.overwriteChainableMethod('foo', fn, fn);
|
||||
*
|
||||
* Then can be used as any other assertion.
|
||||
*
|
||||
* expect(myFoo).to.have.length(3);
|
||||
* expect(myFoo).to.have.length.above(3);
|
||||
*
|
||||
* @param {Object} ctx object whose method / property is to be overwritten
|
||||
* @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
|
||||
* @name overwriteChainableMethod
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function (ctx, name, method, chainingBehavior) {
|
||||
var index = 0;
|
||||
var chainableMethods = addChainableMethod.methods[name];
|
||||
|
||||
// doing a brute-force sequential search for the reference to the object in
|
||||
// question, so we can get its original method and chaining behavior. yep.
|
||||
// there is a danger of this running very slowly (O of n), but it's difficult
|
||||
// for me to imagine n ever getting longer than, well, 1.
|
||||
while(index < chainableMethods.length) {
|
||||
if (chainableMethods[index].ctx === ctx) break;
|
||||
++index;
|
||||
}
|
||||
|
||||
var _chainingBehavior = chainableMethods[index].chainingBehavior;
|
||||
chainableMethods[index].chainingBehavior = function () {
|
||||
var result = chainingBehavior(_chainingBehavior).call(this);
|
||||
return result === undefined ? this : result;
|
||||
};
|
||||
|
||||
var _method = chainableMethods[index].method;
|
||||
chainableMethods[index].method = function () {
|
||||
var result = method(_method).apply(this, arguments);
|
||||
return result === undefined ? this : result;
|
||||
};
|
||||
};
|
|
@ -263,5 +263,47 @@ describe('utilities', function () {
|
|||
expect(obj).x.to.be.ok;
|
||||
expect(obj).to.have.property('__x', 'X!');
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
it('overwriteChainableMethod', function () {
|
||||
chai.use(function (_chai, _) {
|
||||
_chai.Assertion.overwriteChainableMethod('x',
|
||||
function(_super) {
|
||||
return function() {
|
||||
if (_.flag(this, 'marked')) {
|
||||
new chai.Assertion(this._obj).to.be.equal('spot');
|
||||
} else {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
, function(_super) {
|
||||
return function() {
|
||||
_.flag(this, 'message', 'x marks the spot');
|
||||
_super.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Make sure the original behavior of 'x' remains the same
|
||||
expect('foo').x.to.equal("foo");
|
||||
expect("x").x();
|
||||
expect(function () {
|
||||
expect("foo").x();
|
||||
}).to.throw(_chai.AssertionError);
|
||||
var obj = {};
|
||||
expect(obj).x.to.be.ok;
|
||||
expect(obj).to.have.property('__x', 'X!');
|
||||
|
||||
// Test the new behavior of 'x'
|
||||
var assertion = expect('foo').x.to.be.ok;
|
||||
expect(_.flag(assertion, 'message')).to.equal('x marks the spot');
|
||||
expect(function () {
|
||||
var assertion = expect('x');
|
||||
_.flag(assertion, 'marked', true);
|
||||
assertion.x()
|
||||
}).to.throw(_chai.AssertionError);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue