import { expect } from "chai";
class Exception {}
describe("chai", () => {
it("should handle thrown object", () => {
expect(()=> {
throw new Exception();
}).to.throw(Exception);
});
});
1) chai
should handle thrown object:
AssertionError: expected [Function] to throw 'Exception' but {} was thrown
currently have to wrap as follows:
````
import { expect } from "chai";
class SentinelNoError {}
const sentinelNoError = new SentinelNoError();
function returnCatch(fn: ()=>void): any {
try {
fn();
return sentinelNoError;
} catch(error) {
return error;
}
}
class Exception {}
describe("chai", () => {
it("should handle thrown object", () => {
expect(returnCatch(()=> {
throw new Exception();
})).to.be.instanceof(Exception);
});
});
````
Hey @jseter thanks for the issue.
Right now Chai is designed as such that only subclasses of Error can be thrown. We believe this is how code should be written. In your case Exception should extend from error, then you will find it works:
import { expect } from "chai";
class Exception extends Error {}
describe("chai", () => {
it("should handle thrown object", () => {
expect(()=> {
throw new Exception();
}).to.throw(Exception);
});
});
I'm going to close this because, as I say, we intend this to work this way. Feel free to continue the discussion though, perhaps if you can provide us with some good motivating use cases as to why we should change this, we will.
While I understand the logic and in a perfect world would agree, JavaScript doesn't enforce types that can be thrown. A test library shouldn't be enforcing its own version of standards.
I use composition instead of inheritance, one reason being: Typescript Breaking Changes
This also covers the case where the error may be wrapped in a proxy.
perhaps a compromise would be to type the throws call to only accept functions that extend Error and provide an alternative with a predicate statement so the user can supply their own validation (like instanceof).
@jseter The ability to provide arguments inside of the .throw assertion is just meant as a shortcut for the most common use cases, allowing a user to perform multiple assertions internally on the thrown value with a single assertion. It's not meant to cover every possibility. The more possibilities it covers, the more complex (for Chai) and troublesome (for users) the code becomes, as described here.
Although this branch hasn't been merged into Chai yet, the approach documented here should work for you in the current version of Chai.
import { expect } from "chai";
class Exception {}
describe("chai", () => {
it("should handle thrown object", () => {
expect(()=> {
throw new Exception();
}).to.throw().an.instanceof(Exception);
});
});
Hi @meeber , it is good to know the existence of expect().to.throw().an.instanceof(), which also solves my problem.
In my project, I also have to throw something that is not derived from Error. The throw assertion is a little confusing, since I'm expecting that _something_ is thrown when the function runs, independent if _something_ is an Error or anything else. Maybe throw is more like throwError?
@liuxh0 The good news is that using the .throw() assertion without any parameters causes it to only care about whether or not the function threw. It doesn't care if an Error object was thrown, or some other object, or a string, or even undefined. And you can chain any of Chai's other assertions (e.g., instanceof) afterward to make assertions on the thrown value.
The behavior of .throw when one or more parameters are passed isn't quite right, I think. It's likely that the solution I worked on last year isn't perfect either. It's a fair point that .throw shouldn't care what type of value is thrown, even when passing parameters to .throw; otherwise, as you said, it'd be more like .throwError in that case.
Most helpful comment
@jseter The ability to provide arguments inside of the
.throwassertion is just meant as a shortcut for the most common use cases, allowing a user to perform multiple assertions internally on the thrown value with a single assertion. It's not meant to cover every possibility. The more possibilities it covers, the more complex (for Chai) and troublesome (for users) the code becomes, as described here.Although this branch hasn't been merged into Chai yet, the approach documented here should work for you in the current version of Chai.