diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 09d0a6f28..085d20900 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -1601,28 +1601,25 @@ module.exports = function (chai, _) { var target = flag(this, 'object') var ssfi = flag(this, 'ssfi'); var flagMsg = flag(this, 'message'); - var validInstanceOfTarget = constructor === Object(constructor) && ( - typeof constructor === 'function' || - (typeof Symbol !== 'undefined' && - typeof Symbol.hasInstance !== 'undefined' && - Symbol.hasInstance in constructor) - ); - if (!validInstanceOfTarget) { - flagMsg = flagMsg ? flagMsg + ': ' : ''; - var constructorType = constructor === null ? 'null' : typeof constructor; - throw new AssertionError( - flagMsg + 'The instanceof assertion needs a constructor but ' + constructorType + ' was given.', - undefined, - ssfi - ); + try { + var isInstanceOf = target instanceof constructor; + } catch (err) { + if (err instanceof TypeError) { + flagMsg = flagMsg ? flagMsg + ': ' : ''; + throw new AssertionError( + flagMsg + 'The instanceof assertion needs a constructor but ' + + _.type(constructor) + ' was given.', + undefined, + ssfi + ); + } + throw err; } - var isInstanceOf = target instanceof constructor - var name = _.getName(constructor); if (name === null) { - name = 'an unnamed constructor'; + name = 'an unnamed constructor'; } this.assert( diff --git a/test/assert.js b/test/assert.js index 44bb5ff9f..5994d88be 100644 --- a/test/assert.js +++ b/test/assert.js @@ -145,6 +145,17 @@ describe('assert', function () { function Foo(){} assert.instanceOf(new Foo(), Foo); + // Normally, `instanceof` requires that the constructor be a function or an + // object with a callable `@@hasInstance`. But in some older browsers such + // as IE11, `instanceof` also accepts DOM-related interfaces such as + // `HTMLElement`, despite being non-callable objects in those browsers. + // See: https://github.com/chaijs/chai/issues/1000. + if (typeof document !== 'undefined' && + typeof document.createElement !== 'undefined' && + typeof HTMLElement !== 'undefined') { + assert.instanceOf(document.createElement('div'), HTMLElement); + } + err(function(){ assert.instanceOf(new Foo(), 1, 'blah'); }, "blah: The instanceof assertion needs a constructor but number was given."); @@ -155,7 +166,7 @@ describe('assert', function () { err(function(){ assert.instanceOf(new Foo(), {}); - }, "The instanceof assertion needs a constructor but object was given."); + }, "The instanceof assertion needs a constructor but Object was given."); err(function(){ assert.instanceOf(new Foo(), true); @@ -224,7 +235,7 @@ describe('assert', function () { err(function(){ assert.notInstanceOf(new Foo(), {}); - }, "The instanceof assertion needs a constructor but object was given."); + }, "The instanceof assertion needs a constructor but Object was given."); err(function(){ assert.notInstanceOf(new Foo(), true); diff --git a/test/expect.js b/test/expect.js index 484edd6f5..c14fdfa8f 100644 --- a/test/expect.js +++ b/test/expect.js @@ -374,6 +374,17 @@ describe('expect', function () { function Foo(){} expect(new Foo()).to.be.an.instanceof(Foo); + // Normally, `instanceof` requires that the constructor be a function or an + // object with a callable `@@hasInstance`. But in some older browsers such + // as IE11, `instanceof` also accepts DOM-related interfaces such as + // `HTMLElement`, despite being non-callable objects in those browsers. + // See: https://github.com/chaijs/chai/issues/1000. + if (typeof document !== 'undefined' && + typeof document.createElement !== 'undefined' && + typeof HTMLElement !== 'undefined') { + expect(document.createElement('div')).to.be.an.instanceof(HTMLElement); + } + err(function(){ expect(new Foo()).to.an.instanceof(1, 'blah'); }, "blah: The instanceof assertion needs a constructor but number was given."); @@ -388,7 +399,7 @@ describe('expect', function () { err(function(){ expect(new Foo()).to.an.instanceof({}); - }, "The instanceof assertion needs a constructor but object was given."); + }, "The instanceof assertion needs a constructor but Object was given."); err(function(){ expect(new Foo()).to.an.instanceof(true); diff --git a/test/should.js b/test/should.js index ebff98c1f..4ed205aec 100644 --- a/test/should.js +++ b/test/should.js @@ -420,6 +420,17 @@ describe('should', function() { function Foo(){} new Foo().should.be.an.instanceof(Foo); + // Normally, `instanceof` requires that the constructor be a function or an + // object with a callable `@@hasInstance`. But in some older browsers such + // as IE11, `instanceof` also accepts DOM-related interfaces such as + // `HTMLElement`, despite being non-callable objects in those browsers. + // See: https://github.com/chaijs/chai/issues/1000. + if (typeof document !== 'undefined' && + typeof document.createElement !== 'undefined' && + typeof HTMLElement !== 'undefined') { + document.createElement('div').should.be.an.instanceof(HTMLElement); + } + err(function(){ new Foo().should.be.an.instanceof(1, 'blah'); }, "blah: The instanceof assertion needs a constructor but number was given."); @@ -430,7 +441,7 @@ describe('should', function() { err(function(){ new Foo().should.be.an.instanceof({}); - }, "The instanceof assertion needs a constructor but object was given."); + }, "The instanceof assertion needs a constructor but Object was given."); err(function(){ new Foo().should.be.an.instanceof(true);