diff --git a/lib/chai/config.js b/lib/chai/config.js index a9f9a1527..9c8be3cff 100644 --- a/lib/chai/config.js +++ b/lib/chai/config.js @@ -70,5 +70,25 @@ module.exports = { * @api public */ - useProxy: true + useProxy: true, + + /** + * ### config.proxyExcludedKeys + * + * User configurable property, defines which properties should be ignored + * instead of throwing an error if they do not exist on the assertion. + * This is only applied if the environment Chai is running in supports proxies and + * if the `useProxy` configuration setting is enabled. + * By default, `then` and `inspect` will not throw an error if they do not exist on the + * assertion object because the `.inspect` property is read by `util.inspect` (for example, when + * using `console.log` on the assertion object) and `.then` is necessary for promise type-checking. + * + * // By default these keys will not throw an error if they do not exist on the assertion object + * chai.config.proxyExcludedKeys = ['then', 'inspect']; + * + * @param {Array} + * @api public + */ + + proxyExcludedKeys: ['then', 'inspect'] }; diff --git a/lib/chai/utils/proxify.js b/lib/chai/utils/proxify.js index 6baaff260..314421b7e 100644 --- a/lib/chai/utils/proxify.js +++ b/lib/chai/utils/proxify.js @@ -24,10 +24,12 @@ module.exports = function proxify (obj) { return new Proxy(obj, { get: function getProperty (target, property) { - // Don't throw error on Symbol properties such as Symbol.toStringTag, nor - // on .then because it's necessary for promise type-checking. + // This check is here because we should not throw errors on Symbol properties + // such as `Symbol.toStringTag`. + // The values for which an error should be thrown can be configured using + // the `config.proxyExcludedKeys` setting. if (typeof property === 'string' && - property !== 'then' && + config.proxyExcludedKeys.indexOf(property) === -1 && !Reflect.has(target, property)) throw Error('Invalid Chai property: ' + property); diff --git a/test/configuration.js b/test/configuration.js index 991681c04..5eef76c8e 100644 --- a/test/configuration.js +++ b/test/configuration.js @@ -196,4 +196,37 @@ describe('configuration', function () { }); }); }); + + describe('proxyExcludedKeys', function() { + var readNoExistentProperty = function(prop) { + return function() { + var assertion = expect(false); + expect(assertion).to.not.have.key(prop); + assertion[prop]; + } + }; + + it('should have default value equal to `[\'then\', \'inspect\']`', function() { + expect(chai.config.proxyExcludedKeys).to.be.deep.equal(['then', 'inspect']); + }); + + it('should not throw when accessing non-existing `then` and `inspect` in an environment with proxy support', function() { + // Since these will not throw if the environment does not support proxies we don't need any `if` clause here + expect(readNoExistentProperty('then')).to.not.throw(); + expect(readNoExistentProperty('inspect')).to.not.throw(); + }); + + it('should throw for properties which are not on the `proxyExcludedKeys` Array in an environment with proxy support', function() { + chai.config.proxyExcludedKeys = []; + + if (typeof Proxy !== 'undefined' && typeof Reflect !== 'undefined') { + expect(readNoExistentProperty('then')).to.throw('Invalid Chai property: then'); + expect(readNoExistentProperty('inspect')).to.throw('Invalid Chai property: inspect'); + } else { + expect(readNoExistentProperty('then')).to.not.throw(); + expect(readNoExistentProperty('inspect')).to.not.throw(); + } + }); + }); + });