New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw error when instanceof is passed something that is not a function as constructor #899

Merged
merged 1 commit into from Mar 23, 2017
Jump to file or symbol
Failed to load files and symbols.
+271 −26
Diff settings

Always

Just for now

@@ -988,9 +988,29 @@ 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 Symbol.hasInstance !== 'undefined' &&
Symbol.hasInstance in constructor)
);
if (!validInstanceOfTarget) {
var constructorType = constructor === null ? 'null' : typeof constructor;
throw new Error('The instanceof assertion needs a constructor but ' + constructorType + ' was given.');

This comment has been minimized.

@shvaikalesh

shvaikalesh Feb 4, 2017

Member

TypeError fits better

@shvaikalesh

shvaikalesh Feb 4, 2017

Member

TypeError fits better

This comment has been minimized.

@meeber

meeber Feb 4, 2017

Contributor

After this was merged, I was gonna rebase #922 and turn this error into an AssertionError that properly retains ssfi (and then a follow up PR will properly retain the user's custom message).

@meeber

meeber Feb 4, 2017

Contributor

After this was merged, I was gonna rebase #922 and turn this error into an AssertionError that properly retains ssfi (and then a follow up PR will properly retain the user's custom message).

}
var isInstanceOf = target instanceof constructor

This comment has been minimized.

@meeber

meeber Feb 16, 2017

Contributor

Semi-colon :D

@meeber

meeber Feb 16, 2017

Contributor

Semi-colon :D

This comment has been minimized.

@lucasfcosta

lucasfcosta Feb 16, 2017

Member

Thanks!
I miss linting tools 😅

@lucasfcosta

lucasfcosta Feb 16, 2017

Member

Thanks!
I miss linting tools 😅

var name = _.getName(constructor);
if (name === null) {
name = 'an unnamed 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
);
View
@@ -37,7 +37,7 @@
"assertion-error": "^1.0.1",
"check-error": "^1.0.1",
"deep-eql": "^2.0.1",
"get-func-name": "^1.0.0",
"get-func-name": "^2.0.0",
"pathval": "^1.0.0",
"type-detect": "^4.0.0"
},
View
@@ -141,6 +141,60 @@ 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' && typeof Symbol.hasInstance !== 'undefined') {
err(function(){
assert.instanceOf(new Foo(), Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
err(function() {
var FakeConstructor = {};
var fakeInstanceB = 4;
FakeConstructor[Symbol.hasInstance] = function (val) {
return val === 3;
};
assert.instanceOf(fakeInstanceB, FakeConstructor);
}, 'expected 4 to be an instance of an unnamed constructor')
}
err(function () {
assert.instanceOf(5, Foo);
}, "expected 5 to be an instance of Foo");
@@ -156,6 +210,47 @@ 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' && typeof Symbol.hasInstance !== 'undefined') {
err(function(){
assert.notInstanceOf(new Foo(), Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
err(function() {
var FakeConstructor = {};
var fakeInstanceB = 4;
FakeConstructor[Symbol.hasInstance] = function (val) {
return val === 4;
};
assert.notInstanceOf(fakeInstanceB, FakeConstructor);
}, 'expected 4 to not be an instance of an unnamed constructor');
}
err(function () {
assert.notInstanceOf(new Foo(), Foo);
}, "expected {} to not be an instance of Foo");
View
@@ -72,61 +72,61 @@ describe('expect', function () {
expect(42).ok.pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows overwritten property assertion', function () {
err(function () {
expect(42).tmpProperty.pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows uncalled method assertion', function () {
err(function () {
expect(42).equal.pizza;
}, 'Invalid Chai property: equal.pizza. See docs for proper usage of "equal".');
});
it('throws when invalid property follows called method assertion', function () {
err(function () {
expect(42).equal(42).pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows uncalled overwritten method assertion', function () {
err(function () {
expect(42).tmpMethod.pizza;
}, 'Invalid Chai property: tmpMethod.pizza. See docs for proper usage of "tmpMethod".');
});
it('throws when invalid property follows called overwritten method assertion', function () {
err(function () {
expect(42).tmpMethod().pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows uncalled chainable method assertion', function () {
err(function () {
expect(42).a.pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows called chainable method assertion', function () {
err(function () {
expect(42).a('number').pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows uncalled overwritten chainable method assertion', function () {
err(function () {
expect(42).tmpChainableMethod.pizza;
}, 'Invalid Chai property: pizza');
});
it('throws when invalid property follows called overwritten chainable method assertion', function () {
err(function () {
expect(42).tmpChainableMethod().pizza;
}, 'Invalid Chai property: pizza');
});
it('doesn\'t throw if invalid property is excluded via config', function () {
expect(function () {
expect(42).then;
@@ -366,6 +366,71 @@ 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' && typeof Symbol.hasInstance !== 'undefined') {
err(function(){
expect(new Foo()).to.an.instanceof(Symbol());
}, "The instanceof assertion needs a constructor but symbol was given.");
err(function() {
var FakeConstructor = {};
var fakeInstanceB = 4;
FakeConstructor[Symbol.hasInstance] = function (val) {
return val === 3;
};
expect(fakeInstanceB).to.be.an.instanceof(FakeConstructor);
}, 'expected 4 to be an instance of an unnamed constructor')
err(function() {
var FakeConstructor = {};
var fakeInstanceB = 4;
FakeConstructor[Symbol.hasInstance] = function (val) {
return val === 4;
};
expect(fakeInstanceB).to.not.be.an.instanceof(FakeConstructor);
}, 'expected 4 to not be an instance of an unnamed constructor')
}
err(function(){
expect(3).to.an.instanceof(Foo, 'blah');
}, "blah: expected 3 to be an instance of Foo");
@@ -1826,7 +1891,7 @@ describe('expect', function () {
expect(testSet).to.not.have.any.deep.keys([{13: 37}, 'thisDoesNotExist', 'thisToo']);
expect(testSet).to.not.have.any.deep.keys([20, 1, {13: 37}]);
expect(testSet).to.not.have.all.deep.keys([{thisIs: 'anExampleObject'}, {'iDoNot': 'exist'}]);
var weirdSetKey1 = Object.create(null)
, weirdSetKey2 = {toString: NaN}
, weirdSetKey3 = []
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.