The doc says the argument of toThrow() can be a class for the error, it works when a promise throws an Error instance, but fails when the promise throws a custom object.
describe('When a promise throws an expression, rejects.toThrow should match the expression by its type', () => {
it('when the expression is an error', async () => {
const p = new Promise(() => {
throw new Error('some-info');
});
await expect(p).rejects.toThrow(Error); // passed
});
it('when the expression is a custom object', async () => {
class Exception {
constructor(public readonly message: string) {
}
}
const p = new Promise(() => {
throw new Exception('some-info');
});
await expect(p).rejects.toThrow(Exception); // failed
});
});
The first test passes, while the second test fails with the following message:
Expected the function to throw an error of type:
"Exception"
But it didn't throw anything.
Both the above two tests pass.
It passes with the synchronous version, it's just rejects which fails. It also passes if Exception extends Error when using rejects. So it seems to be a bug somehow with rejects.
@BetterCallSky ideas?
May be the test fails because createMatcher checks rejects using isError while Exception is NOT a subclass of Error ?
Behavior for promises changed in #5670. My understanding of toThrow matcher is that it should only pass in case of Error.
To be honest, toThrow matcher doesn't make sense for promises. They just reject when you throw inside them, right?
@peterdanis
toThrow doesn't make sense for resolves, you can check discussion in #6678
I know, before #5670 even expect(someSuccesfulPromise()).resolves.toThrow() passed the test. Nonsense ofcourse.
Therefore I've tried to check, whether object checked in the toThrow matcher (for promises only) is an "error-like" object, otherwise the toThrow matcher would became the same as toEqual. I see in your PR, that assuming "error-like" object was not so good idea :)
But does it make sense to check whether a promise "throws"? Normally one does not use throw in promise, and even if something "throws" inside a promise (e.g. an inner function), it will just reject to thrown value. Afaik promise can only resolve/reject, can't throw.
This is also a problem when throwing objects in async/await that are not Error instances and expecting the toThrow() default with no arguments:
test("Bug in jest", async () => {
expect(() => {
throw "this is fine";
}).toThrow();
await expect(
(async () => {
throw new Error("this is fine too");
})()
).rejects.toThrow();
await expect(
(async () => {
throw "this is not fine";
})()
).rejects.toThrow(); // FAILS TEST
});
Most helpful comment
This is also a problem when throwing objects in async/await that are not Error instances and expecting the
toThrow()default with no arguments: