-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Simplify t.throws() #1047
Comments
I absolutely support your proposal! Answers to your questions:
Services like BugSnag, Sentry, Rollbar, etc will provide zero information, if code throws strings, instead of Error objects.
t.throws(fn, 'string') // Throws an Error (or subclass thereof), whose .message === 'string'
t.throws(fn, /regexp/) // Throws an Error (or subclass thereof), whose /regexp/.test(err.message) === true I use this way constantly and find it very convenient.
|
The current implementation seems to almost match your proposal. I was coming here to file that bug report and submit the PR, but I won't if you're planning to remove it altogether. |
Conclusions so far:
Yes.
We'll support this interface.
Leaning towards not supporting this. @vdemedes
const err1 = new Error()
const err2 = vm.runInNewContext('new Error()')
err1 instanceof Error // true
err2 instanceof Error // false @fearphage yea AVA just uses Node.js' API, and it gets messy fast. Hence this proposal. |
Is it difficult to code or reason about? Just a preference? I'm just curious. If we're target an arity of 2, what about this as an option? t.throws(fn, error => {
// insert error assertions
}); I like the encapsulation of the assertions related to the thrown error. |
The assertion becomes overly complex again, which is what we're trying to move away from.
That'll be hard to distinguish from |
I like the proposal :)
Yes. That is a best practice, or rather, using a string is a bad practice, and we should help the user remove that bad practice from their code IMO.
That is common enough to keep IMO.
I don't custom Error types that much. I think it's rare enough and simple enough to get around it const err = t.throws(fn, 'string');
t.true(err instanceof SyntaxError);
No :/ From what I see, you're proposing the removal of the |
Yes that's implied.
Oh no! Forgot to add that… I think that rules out syntax like |
Alternative proposal. Make it This could easily be an addition to supporting string/regex/constructor in the second argument, for backwards compatibility. For example: t.throws(() => foo(), {
constructor: RangeError,
message: /unicorn pasta is/
}); Compared to the current way: const err = t.throws(() => foo(), /unicorn pasta is/);
t.true(err instanceof RangeError); Possible matchers Benefits of this is that it makes everything explicit. No more wondering for users what We should also have much better validation logic to prevent mistakes. For example, using |
I like it! |
I like Sindre's proposal. It would still return the error for extra assertions, right? Let's say I also want to ensure that multi-line error messages never exceed a certain width, for friendly terminal display. Would it look like this? const err = t.throws(() => foo(), {
constructor: RangeError,
message: /unicorn pasta is/
});
t.is(longestLine(err.message), 80); I will note that there is a much simpler approach to solve the call site ambiguity problem. Just support only constructors in the second argument, since that's the only type that is non-ambiguous for what it is matching. Delegate everything else to |
Yes
It creates verbose code for common cases though. The most common case is wanting to ensure the error is the correct type and has the correct message. I think we should optimize for that. |
Love this proposal. Eliminating the constructor vs. validator function ambiguity would've saved me a lot of time and confusion (example). Is there still something to be done on the 'question' side of things? It's hard to give a helpful push without a clear direction 😄. |
@alextes we can go with @sindresorhus' proposal: #1047 (comment) Match |
I had the need the other day to match against a custom error property. Should we support that too? |
I think that's better served by assigning the thrown error to a variable and asserting on that. |
@sindresorhus I feel the consensus was around supporting common use-cases for error comparison. In other words, offer shortcuts to common comparisons but keep the API surface small as one can already do any comparison with the returned error. 'The other day' only tells us about recency, how about frequency? I think this decision is a tricky balance between frequency, the cost of doing without, and diff potential. Personally I'm leaning towards leaving it out, like novemberborn. @novemberborn I'd actually lean against Sindre's suggestion of possibly adding a One more detail I'd like to bring to the attention of the jury 😄. Sindre Proposal also adds backwards compatibility for the second argument, when not a matcher object, of type string / regex / constructor.
My fingers are starting to itch to write the implementation on this one 😛. |
It's usually better to compare errors using their
It's currently implemented as comparing the message. We should do the same with the regular expression argument, IMO. Historically the problem with the Personally I don't think we should maintain backwards compatibility, given how confusing |
I don't personally need this feature much, but for sake of argument... Say You still need to distinguish between different types of errors and, without the constructor, test(async (t) => {
const option = {
databaseName : 'somethingThatDoesNotExist'
};
t.throws(myApp(option), {
name : 'DatabaseNotFoundError'
});
}); |
Thanks @novemberborn and @sholladay! I understand the need and even preference for I didn't know Ava's Comparing just the message makes a lot of sense to me if we already support the name separately. It would break with Node's behavior. I have no idea how to weigh the two. (I feel your argument to make it simpler is more compelling.)
Happy to be able to contribute something small 😄. |
@alextes thanks! Be sure to check out #1314 which contains a few more changes.
@sholladay, I think Node.js is moving to standardizing error codes, though I couldn't find a definitive proposal on that. File system errors have |
I really don't think we should be excluding valid I lost nearly an entire day because I threw a string, which is fully valid, and |
I don't really think my commentary belongs on this issue, which isn't about throwing strings in any meaningful way, but a maintainer closed the valid and appropriate issue about that explicitly in favor of this one I apologize for what seems to me to be unnecessarily changing the subject |
@StoneCypher When we implement |
Oh, I see that's #1440. |
Thanks. That seems ideal to me. |
Remove `core-assert` dependency. When passed a function as the second argument, `t.throws()` now assumes its a constructor. This removes support for a validation function, which may or may not have worked. Refs #1047. `t.throws()` now fails if the exception is not an error. Fixes #1440. Regular expressions are now matched against the error message, not the result of casting the error to a string. Fixes #1445. Validate second argument to `t.throws()`. Refs #1676.
Remove `core-assert` dependency. When passed a function as the second argument, `t.throws()` now assumes its a constructor. This removes support for a validation function, which may or may not have worked. Refs #1047. `t.throws()` now fails if the exception is not an error. Fixes #1440. Regular expressions are now matched against the error message, not the result of casting the error to a string. Fixes #1445. Validate second argument to `t.throws()`. Refs #1676. Assertion failures now display how AVA arrived at the exception. Constructors are printed when the error is not a correct instance. Fixes #1471.
Remove `core-assert` dependency. When passed a function as the second argument, `t.throws()` now assumes its a constructor. This removes support for a validation function, which may or may not have worked. Refs #1047. `t.throws()` now fails if the exception is not an error. Fixes #1440. Regular expressions are now matched against the error message, not the result of casting the error to a string. Fixes #1445. Validate second argument to `t.throws()`. Refs #1676. Assertion failures now display how AVA arrived at the exception. Constructors are printed when the error is not a correct instance. Fixes #1471.
Fixes #1047. Fixes #1676. A combination of the following expectations is supported: ```js t.throws(fn, {of: SyntaxError}) // err instanceof SyntaxError t.throws(fn, {name: 'SyntaxError'}) // err.name === 'SyntaxError' t.throws(fn, {is: expectedErrorInstance}) // err === expectedErrorInstance t.throws(fn, {message: 'expected error message'}) // err.message === 'expected error message' t.throws(fn, {message: /expected error message/}) // /expected error message/.test(err.message) ```
Remove `core-assert` dependency. When passed a function as the second argument, `t.throws()` now assumes its a constructor. This removes support for a validation function, which may or may not have worked. Refs #1047. `t.throws()` now fails if the exception is not an error. Fixes #1440. Regular expressions are now matched against the error message, not the result of casting the error to a string. Fixes #1445. Validate second argument to `t.throws()`. Refs #1676. Assertion failures now display how AVA arrived at the exception. Constructors are printed when the error is not a correct instance. Fixes #1471.
Fixes #1047. Fixes #1676. A combination of the following expectations is supported: ```js t.throws(fn, {of: SyntaxError}) // err instanceof SyntaxError t.throws(fn, {name: 'SyntaxError'}) // err.name === 'SyntaxError' t.throws(fn, {is: expectedErrorInstance}) // err === expectedErrorInstance t.throws(fn, {message: 'expected error message'}) // err.message === 'expected error message' t.throws(fn, {message: /expected error message/}) // /expected error message/.test(err.message) ```
This is my proposal for resolving #661. In short I want to stop deferring to https://nodejs.org/api/assert.html#assert_assert_throws_block_error_message and remove various parameter overloads that are currently supported by the assertion.
Here's what I'd like to support:
If you need to test the errors class and message you should use the
t.throws
return value:Passing anything other than
undefined
, functions, strings or regular expressions as the second argument results in anTypeError
fromt.throws()
itself.The first argument is allowed to be a promise or observable, as is any return value from the
fn
call. Of course this makest.throws
asynchronous, so users may need to do:Questions:
Does
t.throws(fn, Constructor)
require the thrown value to be anError
? For example:Should
t.throws(fn, 'string')
andt.throws(fn, /regexp/)
be supported at all, or would it be preferable to dereference the error and then use another assertion?Is there a need for
t.throws(fn, SyntaxError, 'string')
andt.throws(fn, SyntaxError, /regexp/)
Does anybody have experience with / examples of asserting
Error
instances across contexts?The text was updated successfully, but these errors were encountered: