-
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
t.throws shows undefined undefined undefined
when a string is thrown
#661
Comments
@SamVerschueren that is expected. With 0.13.0 Note that your examples are different. In the first you reject with a string, in the second with an error. |
Oh ok, I thought that it was still working with 0.13.x. My mistake then. Good to know :). |
I think our output could be better than just |
You're right! |
undefined undefined undefined
when a string is thrown
Just to clear things up a bit regarding this issue. Should AVA handle the case where a dev throws something else then an Error (string, boolean, number, ...)? Or should it show an error that he should throw an error instead? Like implemented in my 2 PRs? |
@SamVerschueren It should return the thrown Error (if it's synchronous). Or a Promise for the rejection reason if an async object is returned (be it Observable or Promise). In other words, The assertion should fail if non- This is complicated enough that we should pretty thoroughly document it. Perhaps it's enough to justify a recipe: "Properly Handling Errors in AVA" that includes detailed explanations on the pitfalls of non-Errors. There is a limited value to grabbing non-Error's, and that is specifically when you are writing a framework or tool that executes user supplied callbacks. In that case it's often beneficial to write a few assertions to define how your code responds when your users code throws non-Errors. Since that's the rarer corner case, you should be responsible for jumping through the extra hoops to assert that behavior (by doing the more verbose thing and wrapping your tests with |
Node's t.throws(fn) // Throws an Error (or subclass thereof)
t.throws(fn, SyntaxError) // Throws a SyntaxError (or subclass thereof)
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 We remove support for validation functions, preferring you use the const err = t.throws(fn, TypeError)
t.true(err.message === 'expecting integer') I'd still be in favor of the string and regular expression expectation shorthand if you're expecting an error but are not too fussed about its inheritance. Not opposed to removing that too and requiring users to run their assertion on the return value. (Also I haven't verified whether Node's While there's a strong convention for throwing proper errors we should still provide an assertion that can capture non-error exceptions. E.g.: const excp = t.throwsAny(fn)
t.true(excp instanceof Foo) |
Is |
while upgrading ava from 0.12 to 0.13 messages like
are not really helpful |
if i'm in favor of pure string rejection reasons, what should i do? |
@iamstarkov Why do you prefer rejecting with strings? |
because it is a at the same time a lot of devs will still use strings as rejection reasons though, and it a bit uncomfortable if testing framework will dictate how promises should be rejected |
It doesn't explicitly promote the usage of a string rejection though, it's just another example - just like the Some (old) food for thought; http://www.devthought.com/2011/12/22/a-string-is-not-an-error/ |
you are right, but i still think that im not the only one and not the last one who will reject using just strings |
i would suggest:
|
While the convention is for throwing errors (or subclasses) I don't think we should preclude users from asserting other values. E.g. I can easily imagine writing code that throws/rejects with object values that don't extend from I'm in favor of |
How about adding a 4th 'loose' parameter to // loose
t.throws(Promise.reject('foo'), null, 'foo', true);
t.throws(() => throw 'foo', null, 'foo', true);
// strict
t.throws(Promise.reject(new Error('foo'), Error, 'foo');
t.throws(() => throw new Error('foo'), Error, 'foo', false); Too much? I don't suppose we could hijack the // loose
t.throws(Promise.reject('foo'), null, true);
// strict
t.throws(Promise.reject(new Error('foo'), Error, 'foo'); No need for a fourth parameter - running assertions on the All of this would change the semantics of |
I think that whether or not throwing a string is allowed should be up to the linter and not the test runner. Given that the language allows you to throw or reject with whatever you want, I would think that t.throws(Promise.reject('foo'), String);
t.throws(Promise.reject('foo'), 'some string');
t.throws(Promise.reject('foo'), /somePattern/); That said, I would never use it, because I use a good linter and only throw Errors. |
We want to promote best practices wherever possible. If you have control of the code, you should be throwing errors.
They show an Error example, and mention that it is probably a good idea to throw Errors. I say it is a code smell. I guess I can live with |
I can't. |
The language lets you throw any value. AVA should (easily!) let you assert the correct value was thrown, whether it's an Perhaps I don't think we should have yet another argument, |
From the first post of @novemberborn in this thread, I assumed that AVA stopped asserting literals being thrown in the code
But when reading further down, it looks like somehow that behaviour broke or was removed without thinking about the consequences. I have a double feeling about the solution of throwing an error when a literal is thrown and force the user to throw/reject with an error. Yes in a perfect world that would be very nice. But this might not be the task of a test runner to force a best practice. It might be up to a linter to force the developer to not throw literals. If we would accept errors and literals, please don't add an extra method like
|
Not really, see #582. AVA used to convert rejection reasons that weren't The Whether
I don't think |
It shouldn't. If you want to do that you can easily try/catch yourself. |
I'm ok with that. Willing to write a small recipe for asserting errors to explain when to use try-catch and when to use |
I'm not sure how that would read. The best practice we want to promote is "Always throw Errors". It's one thing if you are testing code outside your control, but that kind of begs the question: "Why are you testing code outside your control?". (TBH, I have written tests for some closed source API's to verify behavior, but that's really rare). |
@jamestalmage I know, but people will create issues for that as to why it throws an error regarding literals. The recipe could clarify the behaviour and could encourage throwing errors is best practice. A lot of developers don't know that and throw strings for instance. |
Sounds like we just need a good error message. |
It'd be good if after this long discussion somebody could summarize the expected API and behavior of |
Please see #1047 for my proposal on simplifying |
Whilst we haven't simplified the assertion interface yet, the error reporting has improved a lot. Closing this. |
It's not clear why, but I was redirected to this ticket to discuss that I think it's probably counterproductive for This is contrary to the language standard, is not mentioned in the documentation, and is not mentioned in the resulting error text |
Description
When using
t.throws()
with a promise that rejects with a string instead of an Error object, the assertion fails.When using
Promise.reject(new Error('foo'));
, it works as expected.It's due to these lines. I have no idea why it overrides the
err
reference with a function. I looked intocore-assert
and it doesn't seem like it works with passing in a function as theexpected
parameter. But might be missing something here.Environment
Node.js v4.2.1
darwin 15.3.0
The text was updated successfully, but these errors were encountered: