Skip to content

Commit

Permalink
fix: .instanceof to allow DOM interfaces in IE11
Browse files Browse the repository at this point in the history
  • Loading branch information
meeber committed Jul 24, 2017
1 parent df9073c commit c107abb
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 deletions.
31 changes: 14 additions & 17 deletions lib/chai/core/assertions.js
Expand Up @@ -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(
Expand Down
15 changes: 13 additions & 2 deletions test/assert.js
Expand Up @@ -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.");
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion test/expect.js
Expand Up @@ -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.");
Expand All @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion test/should.js
Expand Up @@ -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.");
Expand All @@ -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);
Expand Down

0 comments on commit c107abb

Please sign in to comment.