diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index ac838837e..8c3b0d322 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -888,6 +888,55 @@ module.exports = function (chai, _) { Assertion.addMethod('ownProperty', assertOwnProperty); Assertion.addMethod('haveOwnProperty', assertOwnProperty); + /** + * ### .ownPropertyDescriptor(name[, descriptor[, message]]) + * + * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. + * + * expect('test').to.have.ownPropertyDescriptor('length'); + * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); + * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); + * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); + * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); + * + * @name ownPropertyDescriptor + * @alias haveOwnPropertyDescriptor + * @param {String} name + * @param {Object} descriptor _optional_ + * @param {String} message _optional_ + * @api public + */ + + function assertOwnPropertyDescriptor (name, descriptor, msg) { + if (typeof descriptor === 'string') { + msg = descriptor; + descriptor = null; + } + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); + if (actualDescriptor && descriptor) { + this.assert( + _.eql(descriptor, actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) + , descriptor + , actualDescriptor + , true + ); + } else { + this.assert( + actualDescriptor + , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) + , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) + ); + } + flag(this, 'object', actualDescriptor); + } + + Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); + Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); + /** * ### .length(value) * diff --git a/test/expect.js b/test/expect.js index 0d11c67e6..f41e81bd3 100644 --- a/test/expect.js +++ b/test/expect.js @@ -467,7 +467,7 @@ describe('expect', function () { err(function(){ expect(deepObj).to.have.deep.property('teas[3].tea', 'bar'); }, "expected { Object (green, teas) } to have a deep property 'teas[3].tea'"); - + var arr = [ [ 'chai', 'matcha', 'konacha' ] , [ { tea: 'chai' } @@ -531,6 +531,40 @@ describe('expect', function () { }, "blah: expected { length: 12 } to not have own property 'length'"); }); + it('ownPropertyDescriptor(name)', function(){ + expect('test').to.have.ownPropertyDescriptor('length'); + expect('test').to.haveOwnPropertyDescriptor('length'); + expect('test').not.to.have.ownPropertyDescriptor('foo'); + + var obj = {}; + var descriptor = { + configurable: false, + enumerable: true, + writable: true, + value: NaN + }; + Object.defineProperty(obj, 'test', descriptor); + expect(obj).to.have.ownPropertyDescriptor('test', descriptor); + err(function(){ + expect(obj).not.to.have.ownPropertyDescriptor('test', descriptor, 'blah'); + }, "blah: expected the own property descriptor for 'test' on { test: NaN } to not match { configurable: false,\n enumerable: true,\n writable: true,\n value: NaN }"); + err(function(){ + var wrongDescriptor = { + configurable: false, + enumerable: true, + writable: false, + value: NaN + }; + expect(obj).to.have.ownPropertyDescriptor('test', wrongDescriptor, 'blah'); + }, "blah: expected the own property descriptor for 'test' on { test: NaN } to match { configurable: false,\n enumerable: true,\n writable: false,\n value: NaN }, got { value: NaN,\n writable: true,\n enumerable: true,\n configurable: false }"); + + err(function(){ + expect(obj).to.have.ownPropertyDescriptor('test2', 'blah'); + }, "blah: expected { test: NaN } to have an own property descriptor for 'test2'"); + + expect(obj).to.have.ownPropertyDescriptor('test').and.have.property('enumerable', true); + }); + it('string()', function(){ expect('foobar').to.have.string('bar'); expect('foobar').to.have.string('foo'); diff --git a/test/should.js b/test/should.js index 4c18e03b0..a1a829ffd 100644 --- a/test/should.js +++ b/test/should.js @@ -396,6 +396,40 @@ describe('should', function() { }, "blah: expected { length: 12 } to not have own property 'length'"); }); + it('ownPropertyDescriptor(name)', function(){ + 'test'.should.haveOwnPropertyDescriptor('length'); + 'test'.should.have.ownPropertyDescriptor('length'); + 'test'.should.not.have.ownPropertyDescriptor('foo'); + + var obj = { }; + var descriptor = { + configurable: false, + enumerable: true, + writable: true, + value: NaN + }; + Object.defineProperty(obj, 'test', descriptor); + obj.should.haveOwnPropertyDescriptor('test', descriptor); + err(function(){ + obj.should.not.haveOwnPropertyDescriptor('test', descriptor, 'blah'); + }, "blah: expected the own property descriptor for 'test' on { test: NaN } to not match { configurable: false,\n enumerable: true,\n writable: true,\n value: NaN }"); + err(function(){ + var wrongDescriptor = { + configurable: false, + enumerable: true, + writable: false, + value: NaN + }; + obj.should.haveOwnPropertyDescriptor('test', wrongDescriptor, 'blah'); + }, "blah: expected the own property descriptor for 'test' on { test: NaN } to match { configurable: false,\n enumerable: true,\n writable: false,\n value: NaN }, got { value: NaN,\n writable: true,\n enumerable: true,\n configurable: false }"); + + err(function(){ + obj.should.haveOwnPropertyDescriptor('test2', 'blah'); + }, "blah: expected { test: NaN } to have an own property descriptor for 'test2'"); + + obj.should.have.ownPropertyDescriptor('test').and.have.property('enumerable', true); + }); + it('string()', function(){ 'foobar'.should.contain.string('bar'); 'foobar'.should.contain.string('foo');