Skip to content

Commit

Permalink
Throw error when instanceof is passed something that is not a functio…
Browse files Browse the repository at this point in the history
…n as constructor
  • Loading branch information
lucasfcosta committed Jan 16, 2017
1 parent 877dde8 commit 2c4fc89
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 1 deletion.
21 changes: 20 additions & 1 deletion lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -988,9 +988,28 @@ module.exports = function (chai, _) {

function assertInstanceOf (constructor, msg) {
if (msg) flag(this, 'message', msg);

var target = flag(this, 'object')
var validInstanceOfTarget = constructor === Object(constructor) && (
typeof constructor === 'function' ||
(typeof Symbol !== 'undefined' && typeof constructor[Symbol.hasInstance] === 'function')
);

if (!validInstanceOfTarget) {
var constructorType = constructor === null ? 'null' : typeof constructor;
throw new Error('The instanceof assertion needs a constructor but ' + constructorType + ' was given.');
}

var isInstanceOf;
try {
isInstanceOf = target instanceof constructor
} catch (err) {
throw new Error(target + ' instanceof ' + constructor + ' failed: ' + err.message + '.')
}

var name = _.getName(constructor);
this.assert(
flag(this, 'object') instanceof constructor
isInstanceOf
, 'expected #{this} to be an instance of ' + name
, 'expected #{this} to not be an instance of ' + name
);
Expand Down
74 changes: 74 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,50 @@ describe('assert', function () {
function Foo(){}
assert.instanceOf(new Foo(), Foo);

err(function(){
assert.instanceOf(new Foo(), 1);
}, "The instanceof assertion needs a constructor but number was given.");

err(function(){
assert.instanceOf(new Foo(), 'batman');
}, "The instanceof assertion needs a constructor but string was given.");

err(function(){
assert.instanceOf(new Foo(), {});
}, "The instanceof assertion needs a constructor but object was given.");

err(function(){
assert.instanceOf(new Foo(), true);
}, "The instanceof assertion needs a constructor but boolean was given.");

err(function(){
assert.instanceOf(new Foo(), null);
}, "The instanceof assertion needs a constructor but null was given.");

err(function(){
assert.instanceOf(new Foo(), undefined);
}, "The instanceof assertion needs a constructor but undefined was given.");

var expectedError;
try {
t instanceof Thing;
} catch (err) {
errMsg = '[object Object] instanceof function Thing(){} failed: ' + err.message + '.';
}

err(function(){
function Thing(){};
var t = new Thing();
Thing.prototype = 1337;
assert.instanceOf(t, Thing);
}, expectedError);

if (typeof Symbol !== 'undefined') {
err(function(){
assert.instanceOf(new Foo(), Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
}

err(function () {
assert.instanceOf(5, Foo);
}, "expected 5 to be an instance of Foo");
Expand All @@ -156,6 +200,36 @@ describe('assert', function () {
function Foo(){}
assert.notInstanceOf(new Foo(), String);

err(function(){
assert.notInstanceOf(new Foo(), 1);
}, "The instanceof assertion needs a constructor but number was given.");

err(function(){
assert.notInstanceOf(new Foo(), 'batman');
}, "The instanceof assertion needs a constructor but string was given.");

err(function(){
assert.notInstanceOf(new Foo(), {});
}, "The instanceof assertion needs a constructor but object was given.");

err(function(){
assert.notInstanceOf(new Foo(), true);
}, "The instanceof assertion needs a constructor but boolean was given.");

err(function(){
assert.notInstanceOf(new Foo(), null);
}, "The instanceof assertion needs a constructor but null was given.");

err(function(){
assert.notInstanceOf(new Foo(), undefined);
}, "The instanceof assertion needs a constructor but undefined was given.");

if (typeof Symbol !== 'undefined') {
err(function(){
assert.notInstanceOf(new Foo(), Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
}

err(function () {
assert.notInstanceOf(new Foo(), Foo);
}, "expected {} to not be an instance of Foo");
Expand Down
45 changes: 45 additions & 0 deletions test/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,51 @@ describe('expect', function () {
function Foo(){}
expect(new Foo()).to.be.an.instanceof(Foo);

err(function(){
expect(new Foo()).to.an.instanceof(1);
}, "The instanceof assertion needs a constructor but number was given.");

err(function(){
expect(new Foo()).to.an.instanceof('batman');
}, "The instanceof assertion needs a constructor but string was given.");

err(function(){
expect(new Foo()).to.an.instanceof({});
}, "The instanceof assertion needs a constructor but object was given.");

err(function(){
expect(new Foo()).to.an.instanceof(true);
}, "The instanceof assertion needs a constructor but boolean was given.");

err(function(){
expect(new Foo()).to.an.instanceof(null);
}, "The instanceof assertion needs a constructor but null was given.");

err(function(){
expect(new Foo()).to.an.instanceof(undefined);
}, "The instanceof assertion needs a constructor but undefined was given.");

// Different browsers may have different error messages
var expectedError;
try {
t instanceof Thing;
} catch (err) {
errMsg = '[object Object] instanceof function Thing(){} failed: ' + err.message + '.';
}

err(function(){
function Thing(){};
var t = new Thing();
Thing.prototype = 1337;
expect(t).to.an.instanceof(Thing);
}, expectedError)

if (typeof Symbol !== 'undefined') {
err(function(){
expect(new Foo()).to.an.instanceof(Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
}

err(function(){
expect(3).to.an.instanceof(Foo, 'blah');
}, "blah: expected 3 to be an instance of Foo");
Expand Down
45 changes: 45 additions & 0 deletions test/should.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,51 @@ describe('should', function() {
function Foo(){}
new Foo().should.be.an.instanceof(Foo);

err(function(){
new Foo().should.be.an.instanceof(1);
}, "The instanceof assertion needs a constructor but number was given.");

err(function(){
new Foo().should.be.an.instanceof('batman');
}, "The instanceof assertion needs a constructor but string was given.");

err(function(){
new Foo().should.be.an.instanceof({});
}, "The instanceof assertion needs a constructor but object was given.");

err(function(){
new Foo().should.be.an.instanceof(true);
}, "The instanceof assertion needs a constructor but boolean was given.");

err(function(){
new Foo().should.be.an.instanceof(null);
}, "The instanceof assertion needs a constructor but null was given.");

err(function(){
new Foo().should.be.an.instanceof(undefined);
}, "The instanceof assertion needs a constructor but undefined was given.");

// Different browsers may have different error messages
var expectedError;
try {
t instanceof Thing;
} catch (err) {
errMsg = '[object Object] instanceof function Thing(){} failed: ' + err.message + '.';
}

err(function(){
function Thing(){};
var t = new Thing();
Thing.prototype = 1337;
t.should.be.an.instanceof(Thing);
}, expectedError);

if (typeof Symbol !== 'undefined') {
err(function(){
new Foo().should.be.an.instanceof(Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
}

err(function(){
(3).should.an.instanceof(Foo, 'blah');
}, "blah: expected 3 to be an instance of Foo");
Expand Down

0 comments on commit 2c4fc89

Please sign in to comment.