diff --git a/lib/chai/utils/addChainableMethod.js b/lib/chai/utils/addChainableMethod.js index d2c320992..2c05d33e0 100644 --- a/lib/chai/utils/addChainableMethod.js +++ b/lib/chai/utils/addChainableMethod.js @@ -8,9 +8,10 @@ * Module dependencies */ -var transferFlags = require('./transferFlags'); +var chai = require('../../chai'); var flag = require('./flag'); var proxify = require('./proxify'); +var transferFlags = require('./transferFlags'); /*! * Module variables @@ -82,7 +83,14 @@ module.exports = function (ctx, name, method, chainingBehavior) { if (old_ssfi) flag(this, 'ssfi', assert); var result = chainableBehavior.method.apply(this, arguments); - return result === undefined ? this : result; + + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; // Use `__proto__` if available diff --git a/lib/chai/utils/overwriteChainableMethod.js b/lib/chai/utils/overwriteChainableMethod.js index 1ef7439cc..53be8a73f 100644 --- a/lib/chai/utils/overwriteChainableMethod.js +++ b/lib/chai/utils/overwriteChainableMethod.js @@ -4,6 +4,9 @@ * MIT Licensed */ +var chai = require('../../chai'); +var transferFlags = require('./transferFlags'); + /** * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) * @@ -43,12 +46,24 @@ module.exports = function (ctx, name, method, chainingBehavior) { var _chainingBehavior = chainableBehavior.chainingBehavior; chainableBehavior.chainingBehavior = function () { var result = chainingBehavior(_chainingBehavior).call(this); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; var _method = chainableBehavior.method; chainableBehavior.method = function () { var result = method(_method).apply(this, arguments); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; }; }; diff --git a/lib/chai/utils/overwriteMethod.js b/lib/chai/utils/overwriteMethod.js index 4c61c181e..9e2c11285 100644 --- a/lib/chai/utils/overwriteMethod.js +++ b/lib/chai/utils/overwriteMethod.js @@ -4,7 +4,9 @@ * MIT Licensed */ +var chai = require('../../chai'); var flag = require('./flag'); +var transferFlags = require('./transferFlags'); /** * ### overwriteMethod (ctx, name, fn) @@ -59,6 +61,12 @@ module.exports = function (ctx, name, method) { var result = method(_super).apply(this, arguments); flag(this, 'keep_ssfi', false); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; } }; diff --git a/lib/chai/utils/overwriteProperty.js b/lib/chai/utils/overwriteProperty.js index fa5452f0f..155ccbdab 100644 --- a/lib/chai/utils/overwriteProperty.js +++ b/lib/chai/utils/overwriteProperty.js @@ -4,7 +4,9 @@ * MIT Licensed */ +var chai = require('../../chai'); var flag = require('./flag'); +var transferFlags = require('./transferFlags'); /** * ### overwriteProperty (ctx, name, fn) @@ -58,7 +60,13 @@ module.exports = function (ctx, name, getter) { var result = getter(_super).call(this); flag(this, 'keep_ssfi', false); - return result === undefined ? this : result; + if (result !== undefined) { + return result; + } + + var newAssertion = new chai.Assertion(); + transferFlags(this, newAssertion); + return newAssertion; } , configurable: true }); diff --git a/test/utilities.js b/test/utilities.js index 7201eef6f..0f384fe12 100644 --- a/test/utilities.js +++ b/test/utilities.js @@ -209,148 +209,100 @@ describe('utilities', function () { }); }); - it('addMethod', function () { - chai.use(function(_chai, utils) { - expect(_chai.Assertion).to.not.respondTo('eqqqual'); - _chai.Assertion.addMethod('eqqqual', function (str) { - var object = utils.flag(this, 'object'); - new _chai.Assertion(object).to.be.eql(str); - }); - expect(_chai.Assertion).to.respondTo('eqqqual'); - }); - - expect('spec').to.eqqqual('spec'); - }); + describe('addMethod', function() { + var assertionConstructor; - it('addMethod returning result', function () { - chai.use(function(_chai, utils) { - _chai.Assertion.addMethod('result', function () { - return 'result'; - }) - }); + before(function() { + chai.use(function(_chai, utils) { + assertionConstructor = _chai.Assertion; - expect(expect('foo').result()).to.equal('result'); - }); + expect(_chai.Assertion).to.not.respondTo('eqqqual'); + _chai.Assertion.addMethod('eqqqual', function (str) { + var object = utils.flag(this, 'object'); + new _chai.Assertion(object).to.be.eql(str); + }); - it('addMethod returns new assertion with flags copied over', function () { - var assertionConstructor; + _chai.Assertion.addMethod('result', function () { + return 'result'; + }) - chai.use(function(_chai, utils) { - assertionConstructor = _chai.Assertion; - _chai.Assertion.addMethod('returnNewAssertion', function () { - utils.flag(this, 'mySpecificFlag', 'value1'); - utils.flag(this, 'ultraSpecificFlag', 'value2'); - }); + _chai.Assertion.addMethod('returnNewAssertion', function () { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + }); - _chai.Assertion.addMethod('checkFlags', function() { - this.assert( - utils.flag(this, 'mySpecificFlag') === 'value1' && - utils.flag(this, 'ultraSpecificFlag') === 'value2' - , 'expected assertion to have specific flags' - , "this doesn't matter" - ); + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); }); }); - assertion1 = expect('foo'); - assertion2 = assertion1.to.returnNewAssertion(); - - // Checking if a new assertion was returned - expect(assertion1).to.not.be.equal(assertion2); - - // Check if flags were copied - assertion2.checkFlags(); - - // Checking if it's really an instance of an Assertion - expect(assertion2).to.be.instanceOf(assertionConstructor); + after(function() { + delete chai.Assertion.prototype.eqqqual; - // Test chaining `.length` after a method to guarantee it's not a function's - // `length`. Note: 'instanceof' cannot be used here because the test will - // fail in IE 10 due to how addChainableMethod works without __proto__ - // support. Therefore, test the constructor property of length instead. - var anAssertion = expect([1, 2, 3]).to.be.an.instanceof(Array); - expect(anAssertion.length.constructor).to.equal(assertionConstructor); + delete chai.Assertion.prototype.result; - var anotherAssertion = expect([1, 2, 3]).to.have.a.lengthOf(3).and.to.be.ok; - expect(anotherAssertion.length.constructor).to.equal(assertionConstructor); - }); + delete chai.Assertion.prototype.returnNewAssertion; + delete chai.Assertion.prototype.checkFlags; + }); - it('overwriteMethod', function () { - chai.use(function (_chai, _) { - expect(_chai.Assertion).to.respondTo('eqqqual'); - _chai.Assertion.overwriteMethod('eqqqual', function (_super) { - return function (str) { - var object = _.flag(this, 'object'); - if (object == 'cucumber' && str == 'cuke') { - _.flag(this, 'cucumber', true); - } else { - _super.apply(this, arguments); - } - }; - }); + it('addMethod', function () { + expect(chai.Assertion).to.respondTo('eqqqual'); + expect('spec').to.eqqqual('spec'); + }); + it('addMethod returning result', function () { + expect(expect('foo').result()).to.equal('result'); }); - var vege = expect('cucumber').to.eqqqual('cucumber'); - expect(vege.__flags).to.not.have.property('cucumber'); - var cuke = expect('cucumber').to.eqqqual('cuke'); - expect(cuke.__flags).to.have.property('cucumber'); + it('addMethod returns new assertion with flags copied over', function () { + assertion1 = expect('foo'); + assertion2 = assertion1.to.returnNewAssertion(); - chai.use(function (_chai, _) { - expect(_chai.Assertion).to.not.respondTo('doesnotexist'); - _chai.Assertion.overwriteMethod('doesnotexist', function (_super) { - expect(_super).to.be.a('function'); - return function () { - _.flag(this, 'doesnt', true); - } - }); - }); + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); - var dne = expect('something').to.doesnotexist(); - expect(dne.__flags).to.have.property('doesnt'); + // Check if flags were copied + assertion2.checkFlags(); - chai.use(function (_chai, _) { - expect(_chai.Assertion).to.not.respondTo('doesnotexistfail'); - _chai.Assertion.overwriteMethod('doesnotexistfail', function (_super) { - expect(_super).to.be.a('function'); - return function () { - _.flag(this, 'doesnt', true); - _super.apply(this, arguments); - } - }); - }); + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); - var dneFail = expect('something'); - var dneError; - try { dneFail.doesnotexistfail(); } - catch (e) { dneError = e; } - expect(dneFail.__flags).to.have.property('doesnt'); - expect(dneError.message).to.eql('doesnotexistfail is not a function'); - }); + // Test chaining `.length` after a method to guarantee it's not a function's + // `length`. Note: 'instanceof' cannot be used here because the test will + // fail in IE 10 due to how addChainableMethod works without __proto__ + // support. Therefore, test the constructor property of length instead. + var anAssertion = expect([1, 2, 3]).to.be.an.instanceof(Array); + expect(anAssertion.length.constructor).to.equal(assertionConstructor); - it('overwriteMethod returning result', function () { - chai.use(function (_chai, _) { - _chai.Assertion.overwriteMethod('result', function (_super) { - return function () { - return 'result'; - } - }); + var anotherAssertion = expect([1, 2, 3]).to.have.a.lengthOf(3).and.to.be.ok; + expect(anotherAssertion.length.constructor).to.equal(assertionConstructor); }); - - expect(expect('foo').result()).to.equal('result'); }); describe('overwriteMethod', function () { + var assertionConstructor; + before(function() { chai.config.includeStack = false; - chai.use(function(_chai, _) { + chai.use(function(_chai, utils) { + assertionConstructor = _chai.Assertion; + _chai.Assertion.addMethod('four', function() { this.assert(this._obj === 4, 'expected #{this} to be 4', 'expected #{this} to not be 4', 4); }); _chai.Assertion.overwriteMethod('four', function(_super) { return function() { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + if (typeof this._obj === 'string') { this.assert(this._obj === 'four', 'expected #{this} to be \'four\'', 'expected #{this} to not be \'four\'', 'four'); } else { @@ -358,11 +310,92 @@ describe('utilities', function () { } } }); + + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); }); }); after(function() { delete chai.Assertion.prototype.four; + delete chai.Assertion.prototype.checkFlags; + delete chai.Assertion.prototype.eqqqual; + delete chai.Assertion.prototype.doesnotexist; + delete chai.Assertion.prototype.doesnotexistfail; + }); + + it('overwriteMethod', function () { + chai.use(function (_chai, utils) { + _chai.Assertion.addMethod('eqqqual', function (str) { + var object = utils.flag(this, 'object'); + new _chai.Assertion(object).to.be.eql(str); + }); + + _chai.Assertion.overwriteMethod('eqqqual', function (_super) { + return function (str) { + var object = utils.flag(this, 'object'); + if (object == 'cucumber' && str == 'cuke') { + utils.flag(this, 'cucumber', true); + } else { + _super.apply(this, arguments); + } + }; + }); + }); + + var vege = expect('cucumber').to.eqqqual('cucumber'); + expect(vege.__flags).to.not.have.property('cucumber'); + var cuke = expect('cucumber').to.eqqqual('cuke'); + expect(cuke.__flags).to.have.property('cucumber'); + + chai.use(function (_chai, _) { + expect(_chai.Assertion).to.not.respondTo('doesnotexist'); + _chai.Assertion.overwriteMethod('doesnotexist', function (_super) { + expect(_super).to.be.a('function'); + return function () { + _.flag(this, 'doesnt', true); + } + }); + }); + + var dne = expect('something').to.doesnotexist(); + expect(dne.__flags).to.have.property('doesnt'); + + chai.use(function (_chai, _) { + expect(_chai.Assertion).to.not.respondTo('doesnotexistfail'); + _chai.Assertion.overwriteMethod('doesnotexistfail', function (_super) { + expect(_super).to.be.a('function'); + return function () { + _.flag(this, 'doesnt', true); + _super.apply(this, arguments); + } + }); + }); + + var dneFail = expect('something'); + var dneError; + try { dneFail.doesnotexistfail(); } + catch (e) { dneError = e; } + expect(dneFail.__flags).to.have.property('doesnt'); + expect(dneError.message).to.eql('doesnotexistfail is not a function'); + }); + + it('overwriteMethod returning result', function () { + chai.use(function (_chai, _) { + _chai.Assertion.overwriteMethod('result', function (_super) { + return function () { + return 'result'; + } + }); + }); + + expect(expect('foo').result()).to.equal('result'); }); it('calling _super has correct stack trace', function() { @@ -392,110 +425,130 @@ describe('utilities', function () { } } }); - }); - it('addProperty', function () { - chai.use(function (_chai, _) { - _chai.Assertion.addProperty('tea', function () { - _.flag(this, 'tea', 'chai'); - }); - }); + it('should return a new assertion with flags copied over', function () { + var assertion1 = expect('four'); + var assertion2 = assertion1.four(); - var assert = expect('chai').to.be.tea; - expect(assert.__flags.tea).to.equal('chai'); - }); + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); - it('addProperty returns a new assertion with flags copied over', function () { - var assertionConstructor = chai.Assertion; + // Check if flags were copied + assertion2.checkFlags(); - chai.use(function(_chai, utils) { - assertionConstructor = _chai.Assertion; - _chai.Assertion.addProperty('thing', function () { - utils.flag(this, 'mySpecificFlag', 'value1'); - utils.flag(this, 'ultraSpecificFlag', 'value2'); - }); + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); - _chai.Assertion.addMethod('checkFlags', function() { - this.assert( - utils.flag(this, 'mySpecificFlag') === 'value1' && - utils.flag(this, 'ultraSpecificFlag') === 'value2' - , 'expected assertion to have specific flags' - , "this doesn't matter" - ); - }); - }); + // Test chaining `.length` after a method to guarantee it is not a function's `length` + expect('four').to.be.a.four().length.above(2); - assertion1 = expect('foo'); - assertion2 = assertion1.is.thing; + // Ensure that foo returns an Assertion (not a function) + expect(expect('four').four()).to.be.an.instanceOf(assertionConstructor); + }); + }); - // Checking if a new assertion was returned - expect(assertion1).to.not.be.equal(assertion2); + describe('addProperty', function() { + var assertionConstructor = chai.Assertion; - // Check if flags were copied - assertion2.checkFlags(); + before(function() { + chai.use(function (_chai, utils) { + assertionConstructor = _chai.Assertion; - // If it is, calling length on it should return an assertion, not a function - expect([1, 2, 3]).to.be.an.instanceof(Array); + _chai.Assertion.addProperty('tea', function () { + utils.flag(this, 'tea', 'chai'); + }); - // Checking if it's really an instance of an Assertion - expect(assertion2).to.be.instanceOf(assertionConstructor); + _chai.Assertion.addProperty('result', function () { + return 'result'; + }) - // Test chaining `.length` after a property to guarantee it is not a function's `length` - expect([1, 2, 3]).to.be.a.thing.with.length.above(2); - expect([1, 2, 3]).to.be.an.instanceOf(Array).and.have.length.below(4); + _chai.Assertion.addProperty('thing', function () { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + }); - expect(expect([1, 2, 3]).be).to.be.an.instanceOf(assertionConstructor); - expect(expect([1, 2, 3]).thing).to.be.an.instanceOf(assertionConstructor); - }); + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); + }); + }); - it('addProperty returning result', function () { - chai.use(function(_chai, _) { - _chai.Assertion.addProperty('result', function () { - return 'result'; - }) + after(function() { + delete chai.Assertion.prototype.tea; + delete chai.Assertion.prototype.thing; + delete chai.Assertion.prototype.checkFlags; + delete chai.Assertion.prototype.result; }); - expect(expect('foo').result).to.equal('result'); - }); + it('addProperty', function () { + var assert = expect('chai').to.be.tea; + expect(assert.__flags.tea).to.equal('chai'); + }); - it('overwriteProperty', function () { - chai.use(function (_chai, _) { - expect(new chai.Assertion()).to.have.property('tea'); - _chai.Assertion.overwriteProperty('tea', function (_super) { - return function () { - var act = _.flag(this, 'object'); - if (act === 'matcha') { - _.flag(this, 'tea', 'matcha'); - } else { - _super.call(this); - } - } - }); + it('addProperty returning result', function () { + expect(expect('foo').result).to.equal('result'); }); - var matcha = expect('matcha').to.be.tea; - expect(matcha.__flags.tea).to.equal('matcha'); - var assert = expect('something').to.be.tea; - expect(assert.__flags.tea).to.equal('chai'); - }); + it('addProperty returns a new assertion with flags copied over', function () { + assertion1 = expect('foo'); + assertion2 = assertion1.is.thing; - it('overwriteProperty returning result', function () { - chai.use(function(_chai, _) { - _chai.Assertion.overwriteProperty('result', function (_super) { - return function () { - return 'result'; - } - }); - }); + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); + + // Check if flags were copied + assertion2.checkFlags(); + + // If it is, calling length on it should return an assertion, not a function + expect([1, 2, 3]).to.be.an.instanceof(Array); + + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); - expect(expect('foo').result).to.equal('result'); + // Test chaining `.length` after a property to guarantee it is not a function's `length` + expect([1, 2, 3]).to.be.a.thing.with.length.above(2); + expect([1, 2, 3]).to.be.an.instanceOf(Array).and.have.length.below(4); + + expect(expect([1, 2, 3]).be).to.be.an.instanceOf(assertionConstructor); + expect(expect([1, 2, 3]).thing).to.be.an.instanceOf(assertionConstructor); + }); }); describe('overwriteProperty', function () { + var assertionConstructor; + before(function() { chai.config.includeStack = false; - chai.use(function(_chai, _) { + chai.use(function(_chai, utils) { + assertionConstructor = _chai.Assertion; + + _chai.Assertion.addProperty('tea', function () { + utils.flag(this, 'tea', 'chai'); + }); + + _chai.Assertion.overwriteProperty('tea', function (_super) { + return function () { + var act = utils.flag(this, 'object'); + if (act === 'matcha') { + utils.flag(this, 'tea', 'matcha'); + } else { + _super.call(this); + } + } + }); + + _chai.Assertion.overwriteProperty('result', function (_super) { + return function () { + return 'result'; + } + }); + _chai.Assertion.addProperty('four', function() { this.assert(this._obj === 4, 'expected #{this} to be 4', 'expected #{this} to not be 4', 4); }); @@ -509,11 +562,45 @@ describe('utilities', function () { } } }); + + _chai.Assertion.addProperty('foo'); + + _chai.Assertion.overwriteProperty('foo', function (_super) { + return function blah () { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + _super.call(this); + }; + }); + + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); }); }); after(function() { + delete chai.Assertion.prototype.tea; delete chai.Assertion.prototype.four; + delete chai.Assertion.prototype.result; + delete chai.Assertion.prototype.foo; + delete chai.Assertion.prototype.checkFlags + }); + + it('overwriteProperty', function () { + var matcha = expect('matcha').to.be.tea; + expect(matcha.__flags.tea).to.equal('matcha'); + var assert = expect('something').to.be.tea; + expect(assert.__flags.tea).to.equal('chai'); + }); + + it('overwriteProperty returning result', function () { + expect(expect('foo').result).to.equal('result'); }); it('calling _super has correct stack trace', function() { @@ -543,6 +630,30 @@ describe('utilities', function () { } } }); + + it('should return new assertion with flags copied over', function() { + var assertion1 = expect('foo'); + var assertion2 = assertion1.is.foo; + + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); + + // Check if flags were copied + assertion2.checkFlags(); + + // If it is, calling length on it should return an assertion, not a function + expect([1, 2, 3]).to.be.an.foo.length.below(1000); + + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); + + // Test chaining `.length` after a property to guarantee it is not a function's `length` + expect([1, 2, 3]).to.be.a.foo.with.length.above(2); + expect([1, 2, 3]).to.be.an.instanceOf(Array).and.have.length.below(4); + + expect(expect([1, 2, 3]).be).to.be.an.instanceOf(assertionConstructor); + expect(expect([1, 2, 3]).foo).to.be.an.instanceOf(assertionConstructor); + }); }); it('getMessage', function () { @@ -731,24 +842,55 @@ describe('utilities', function () { }); }); - it('addChainableMethod', function () { - chai.use(function (_chai, _) { - _chai.Assertion.addChainableMethod('x', - function () { - new chai.Assertion(this._obj).to.be.equal('x'); - } - , function () { - this._obj = this._obj || {}; - this._obj.__x = 'X!' - } - ); + describe('addChainableMethod', function() { + var assertionConstructor; + + before(function() { + chai.use(function (_chai, utils) { + assertionConstructor = _chai.Assertion; + + _chai.Assertion.addChainableMethod('x', + function () { + new chai.Assertion(this._obj).to.be.equal('x'); + } + , function () { + this._obj = this._obj || {}; + this._obj.__x = 'X!' + } + ); + + _chai.Assertion.addChainableMethod('foo', function(str) { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + var obj = utils.flag(this, 'object'); + new _chai.Assertion(obj).to.be.equal(str); + }); + + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); + }); + }); + + after(function() { + delete chai.Assertion.prototype.x; + delete chai.Assertion.prototype.foo; + delete chai.Assertion.prototype.checkFlags; + }); + + it('addChainableMethod', function () { expect("foo").x.to.equal("foo"); expect("x").x(); expect(function () { expect("foo").x(); - }).to.throw(_chai.AssertionError); + }).to.throw(chai.AssertionError); // Verify whether the original Function properties are present. // see https://github.com/chaijs/chai/commit/514dd6ce4#commitcomment-2593383 @@ -761,47 +903,130 @@ describe('utilities', function () { var obj = {}; expect(obj).x.to.be.ok; expect(obj).to.have.property('__x', 'X!'); - }) + }); + + it('addChainableMethod should return a new assertion with flags copied over', function () { + chai.config.proxyExcludedKeys.push('nodeType'); + + var assertion1 = expect('bar'); + var assertion2 = assertion1.foo('bar'); + + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); + + // Check if flags were copied + assertion2.checkFlags(); + + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); + + // Test chaining `.length` after a method to guarantee it is not a function's `length` + expect('bar').to.be.a.foo('bar').length.above(2); + + // Ensure that foo returns an Assertion (not a function) + expect(expect('bar').foo('bar')).to.be.an.instanceOf(assertionConstructor); + }); }); - 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 { + describe('overwriteChainableMethod', function() { + var assertionConstructor; + var utils; + + before(function() { + chai.use(function (_chai, _utils) { + assertionConstructor = _chai.Assertion; + utils = _utils; + + _chai.Assertion.addChainableMethod('x', + function () { + new chai.Assertion(this._obj).to.be.equal('x'); + } + , function () { + this._obj = this._obj || {}; + this._obj.__x = 'X!' + } + ); + + _chai.Assertion.overwriteChainableMethod('x', + function(_super) { + return function() { + utils.flag(this, 'mySpecificFlag', 'value1'); + utils.flag(this, 'ultraSpecificFlag', 'value2'); + + if (utils.flag(this, 'marked')) { + new chai.Assertion(this._obj).to.be.equal('spot'); + } else { + _super.apply(this, arguments); + } + }; + } + , function(_super) { + return function() { + utils.flag(this, 'message', 'x marks the spot'); _super.apply(this, arguments); - } - }; - } - , function(_super) { - return function() { - _.flag(this, 'message', 'x marks the spot'); - _super.apply(this, arguments); - }; - } - ); + }; + } + ); + _chai.Assertion.addMethod('checkFlags', function() { + this.assert( + utils.flag(this, 'mySpecificFlag') === 'value1' && + utils.flag(this, 'ultraSpecificFlag') === 'value2' && + utils.flag(this, 'message') === 'x marks the spot' + , 'expected assertion to have specific flags' + , "this doesn't matter" + ); + }); + }); + }); + + after(function() { + delete chai.Assertion.prototype.x; + delete chai.Assertion.prototype.checkFlags; + }); + + it('overwriteChainableMethod', function () { // 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); + }).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(utils.flag(assertion, 'message')).to.equal('x marks the spot'); expect(function () { var assertion = expect('x'); - _.flag(assertion, 'marked', true); + utils.flag(assertion, 'marked', true); assertion.x() - }).to.throw(_chai.AssertionError); + }).to.throw(chai.AssertionError); + }); + + it('should return a new assertion with flags copied over', function () { + var assertion1 = expect('x'); + var assertion2 = assertion1.x(); + + chai.config.proxyExcludedKeys.push('nodeType'); + + // Checking if a new assertion was returned + expect(assertion1).to.not.be.equal(assertion2); + + // Check if flags were copied + assertion2.checkFlags(); + + // Checking if it's really an instance of an Assertion + expect(assertion2).to.be.instanceOf(assertionConstructor); + + // Test chaining `.length` after a method to guarantee it is not a function's `length` + expect('x').to.be.x().length.above(0); + + // Ensure that foo returns an Assertion (not a function) + expect(expect('x').x()).to.be.an.instanceOf(assertionConstructor); + expect(expect('x').x).to.be.an.instanceOf(assertionConstructor); }); });