-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
toThrowError() Does Not Support Custom Error Types #4559
Comments
This is an error on chai.js side, - |
I'm not sure if this is a legitimate workaround, but I found this https://stackblitz.com/edit/vitest-dev-vitest-vk98np?file=test%2Fbasic.test.ts test('extract thrown object via async/rejects', async () => {
const func = () => {
throw {
body: {
message: 'Custom error type',
},
};
};
await expect(async () => func()).rejects.toMatchInlineSnapshot(`
{
"body": {
"message": "Custom error type",
},
}
`);
}); I feel there should be non-async version of this pattern, but I'm not sure Jest has such assertion either. |
I was experimenting with such custom assertion. I think this could be implemented in user-land as chai plugin and here is my attempt: https://stackblitz.com/edit/vitest-dev-vitest-c1bw5j?file=test%2Fbasic.test.ts reveal codeimport chai from 'chai';
import { describe, expect, it } from 'vitest';
declare module 'vitest' {
interface Assertion<T = any> {
thrownValue: Assertion<T>;
}
}
chai.use((chai, utils) => {
utils.addProperty(
chai.Assertion.prototype,
'thrownValue',
function __VITEST_REJECTS__(this: any) {
const error = new Error('thrownValue');
utils.flag(this, 'error', error);
const obj = utils.flag(this, 'object');
if (typeof obj !== 'function')
throw new TypeError(
`You must provide a function to expect() when using .throws2, not '${typeof obj}'.`
);
const proxy: any = new Proxy(this, {
get: (target, key, receiver) => {
const result = Reflect.get(target, key, receiver);
if (typeof result !== 'function')
return result instanceof chai.Assertion ? proxy : result;
return (...args: any[]) => {
let value: any;
try {
value = obj();
} catch (err) {
utils.flag(this, 'object', err);
return result.call(this, ...args);
}
const _error = new chai.AssertionError(
`function returned "${utils.inspect(value)}" instead of throwing`,
{ showDiff: true, expected: new Error('throws'), actual: value }
) as any;
_error.stack = (error.stack as string).replace(
error.message,
_error.message
);
throw _error;
};
},
});
return proxy;
}
);
});
//
// example usage
//
describe('thrownValue', () => {
it('basic', () => {
// this would be mostly same as builtin `toThrowErrorMatchingInlineSnapshot`
expect(() => {
throw new Error('hello');
}).thrownValue.toMatchInlineSnapshot('[Error: hello]');
expect(() => {
throw new Error('hello');
}).toThrowErrorMatchingInlineSnapshot(`[Error: hello]`);
// but this allows asserting other than "message"
expect(() => {
throw new Error('hello', { cause: 'world' });
}).thrownValue.toMatchObject({ cause: 'world' });
// also non Error instance
expect(() => {
throw { some: 'object' };
}).thrownValue.toMatchObject({ some: expect.stringContaining('j') });
});
it('expect to throw', () => {
expect(() => {
expect(() => 'all good').thrownValue.toBeDefined();
}).toThrowErrorMatchingInlineSnapshot(
`[AssertionError: function returned "'all good'" instead of throwing]`
);
});
}); I mostly followed how vitest implements vitest/packages/expect/src/jest-expect.ts Line 732 in 0802167
|
Directly changing this would probably be a breaking change, but I agree with this comment:
Another "fix" i'd be happy with is for |
Thanks for referencing the issue from Jest. I've been also wondering whether Jest has considered chain-able synchronous throw at some point. Somehow
Node's For chainable things, this can be already achieved by await expect(() => ...).rejects.toSatisfy((e) => {
expect(e).toMatchInlineSnapshot(`...`);
expect(e.cause).toMatchInlineSnapshot(`...`);
return true
}); Well, looking back the content of the original issue, it's not really about the chainable throw, so probably I should've created a separate feature request. |
@kmanev073 Could this use case be supported by modifying Here's an untested sketch demonstrating ... // implementation.js
export class HttpError extends Error {}
export function myFunction() {
throw new HttpError()
} // test.js
import { HttpError, myFunction } from './implementation.js'
expect(myFunction()).toThrowError(HttpError) In other words, should |
Describe the bug
When a custom object-type error is thrown and a string parameter is passed to
toThrowError()
an unhanded exception is thrown:I guess vitest expects to always receive an error with a message property that has a
indexOf
function. Well... this seems that this is not always the case.This happens with normal and async functions as well.
I found the issue while I was trying to test SvelteKit application where I use the
error()
(link) function which throws a customHttpError
(link).Reproduction
https://stackblitz.com/edit/vitest-dev-vitest-bdugz4?file=test%2Fbasic.test.ts
I've seen this issue issue 1636 but it doesn't explain on how to assert the contents of the object instance that was thrown.
System Info
Used Package Manager
npm
Validations
The text was updated successfully, but these errors were encountered: