-
Notifications
You must be signed in to change notification settings - Fork 2.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
Fail with error & stack trace in asynchronous code #529
Comments
Handling asynchronous errors is something that we would like to look at in future releases in Jasmine. Thanks for sharing your implementation. Unfortunately since Jasmine won't be able to wrap the asynchronous code in a try/catch we'll probably have to end up relying on window.onerror/process.on('uncaughtException'). We've added a story to the backlog to explore this issue here, but happy to look at pull requests as well. |
Correction to above. Since I moved files around, see https://github.com/stevecj/headway/blob/master/spec/indexedDbAdapter/coreSpec.js for example of how the helpers are used. The way I'm applying the try/catch is to have the programmer pass a function to this.asyncStep(...) which then returns a wrapped function. The resulting wrapped function can then be supplied to whatever will make the asynchronous call. |
Ah interesting. Seems like that would work for callback parts of the code in the spec but still not parts of implementation code that could throw? For example in the following code taken from beforeEach( function ( done ) {
this.getSubject().asyncConnect( DB_NAME ).then(
this.asyncStep( function ( db ) {
db.close();
// Only care about calls on re-open, not previous open to create db.
this.getSchema().migrate.calls.reset();
})
).then( done, done );
}); If asyncConnect = function(dbName) {
var promise = new Promise();
setTimeout(1, function() {
dataBaseConnector.connect(dbName).then(function(db) {
promise.resolve(db);
});
});
return promise;
}; This implementation is a bit contrived, but if |
I see what you're saying. In my case, I have taken responsibility (as the developer) for making sure that the code that is likely to throw exceptions can be wrapped, and the only thing I'm relying on the helper to do is to notice the exception and deal with it. The only thing that I've been unhappy about with my helper is that it can't halt the example run when an exception is detected. Of course, it would be nicer if this was magically handled without having to wrap anything, but I'm not sure if that's possible to do in such a way that we can know the error belongs to the current example and not to a previous example that kept running after timeout (happens a lot with mistakes using indexedDB that cause blocking) or to some setInterval handler that never got cleared. |
@stevecj That's a great point. Simply getting an error doesn't mean that we should fail the current spec. Seems like at least currently, minus wrongly assuming the current spec, it would have to be the developers that deal with exceptions that happen in their async code. I'm not really sure how we can proceed. |
IMO, a good step forward would be something similar to the helper I wrote, but that can also halt the example in its currently in-progress step or output the full example name that it belongs to if already timed out. I just had this thought — maybe dumb, or maybe clever. What if the "done" argument could double as as an object with member functions such as the one I'm suggesting for wrapping async substeps (rather than adding a method to "this" as I have been doing)? Perhaps, there could also be a prescribed technique for adding other custom support methods to "done". If this idea sounds good to you, I wouldn't mind attempting to work up a PR. |
If this is still interesting to you, we'd be happy to look at a pull request. I need much more context in order to consider it. |
No time in mys schedule at the moment, but definitely still interesting. I will try to make a PR sometime in the nearish future. |
We have this tracker story (https://www.pivotaltracker.com/story/show/66359332) as well |
I don't know if this is the same or different issue, but I discovered that when I do this somewhere:
then what I get is:
So the reporter thinks that my tests pass... but it actually ran only 16 out of 52 tests I currently have. 😱 |
The fact that the exception does not actually cause the suite to fail is the problem here. I'm not sure why it didn't run all of your tests, and am actually unable to reproduce that issue. |
One more similar issue: when I do:
...it fails some random async spec later. |
@mik01aj that actually doesn't surprise me. Once you get into That is probably not something we're going to worry about, since it's failing the suite and you've basically set it up so jasmine can't figure out where the correct place to put the failure is. |
The issue is when a spec does have a describe('suite', function () {
it('spec 1', function (done) {
// some async code that may eventually throw an exception
setTimeout(function () {
throw 'foo';
done();
});
});
it('spec 2', function () {
expect(true).toBeTruthy();
});
}); The runner will crash while executing spec 1. The remaining specs (spec 2) won't run at all. |
@adrianolek Simply If you are seeing the entire suite stop upon encountering an error in async code, that definitely sounds like a bug. What version of jasmine are you using? Can you reproduce this issue with a small suite of just the two specs? Thanks |
@slackersoft here it is. I've just noticed jasmine/jasmine is the browser runner and I'm using jasmine/jasmine-npm. However the issue seems to be the same. I could add an issue in jasmine-npm if you prefer. |
@adrianolek it sounds like the crash is particular to running the specs in node, since we don't yet have a global exception handler while running specs. We want to get this fixed soon, especially now that I more fully understand how it is affecting the npm runner, but I'm not sure when we'll get some time to look at how best to accomplish this. I would be happy to review a pull request that caught exceptions from async code in both a browser and nodejs context and got that failure to the current runnable to cause the failure. Also see the tracker story for more info. |
@slackersoft thanks for this commit.
I use jasmine via protractor.
Would it be the right pattern to follow, e.g. always do catch-ing and call done.fail in it like in the above example?
and test execution stucks for quite some time as obviously done or done.fail does not get called. The above pattern seems to work great also if an Error is thrown (error and stack trace are logged):
A bit more complex example, which also works nice (provided that the catch "boilerplate" is used at the end):
|
I checked this again with a colleague. It seems to depend on the Node.js version!!!
|
@attila123 Jasmine just uses the Another thing to check is that the Jasmine being run in the different versions is really 2.6.x and not accidentally 2.5 or something. When the error isn't logged, what other behavior are you seeing? Does your suite still pass? Does the spec timeout?, etc. |
I've been testing this today and was hoping someone could confirm the intended behaviour. The following (as of 2.6.1) will fail my test suite: it('fails on an uncaught async error', () => {
// should fail somewhere because of this?
setTimeout(
(() => {
throw 'kaboom';
}),
1
);
}); But the same thing in a Promise will not: it('fails on an uncaught error thrown in a promise', () => {
let prom: Promise<{}> = new Promise((resolve, reject) => {
resolve();
});
prom.then(() => {
throw 'kaboom';
});
}); In the above test - I get the following in my console but all the tests pass. Is this expected?
Thanks |
@slackersoft I double checked that I was on the latest jasmine-core 2.6.1. I checked this fix of yours appeared in node_modules/jasmine-core/lib/jasmine-core/jasmine.js. |
@lathonez: Both of your example tests tell Jasmine that they've passed (in this case by returning without failing) and then later trigger an exception. Jasmine tries to associate that kind of late asynchronous error with the spec that most likely caused it, but it's not an easy problem to solve. #1352 might help in your scenario by routing the errors somewhere useful, but it's also possible that the errors are occurring after Jasmine has reported success. It doesn't surprise me that the promise test behaves differently than the setTimeout tests. Most promise implementations use a more complicated stack-clearing scheme than a simple setTimeout, and that can affect the timing of the error. |
@sgravrock - thank you for getting back to me
We had a test that was fully synchronous, but the implementation changed to be async and the dev didn't update the spec correctly to match. It took me a few weeks to realise the async part of the implementation was failing in Jasmine. The usecase is as per the example - if the code were synchronous the tests would have failed as the implementation threw an error.
I understand - I don't care whether or not the failure is associated with the correct spec - just failing the entire test suite on an uncaught error is good enough for me. This is the behaviour I observed on 2.6.1 with the
Thank you, will keep an eye on this
Not possible in the sense that they are observed in the console long before the suite finishes running. But I guess perhaps before Jasmine has had them bubble up or something?
Agreed. I was trying to understand whether the |
Jasmine finishes running as soon as the last dot is printed, but the full report might take some time to generate in larger suites. I'm releasing 2.6.2 tonight, give that a shot with some of the other fixes, hopefully it will help. Thanks for using Jasmine! |
FYI I've tested on 2.6.2 and have the same behaviour re promises. This is purely for information - I didn't come here expecting a fix for this, just thought it might fix it and wanted to help document behaviour. If others have different results I would be keen to know. @slackersoft thanks for all your work, very happy with Jasmine. |
Hi, I'd like to test a bit jasmine with newer (6.10, 6.11) Node.js. Does anyone know a sample project to add simple jasmine tests to? So that I could simply share some example tests based on that project. |
@attila123 You are more likely to get quicker responses from the community for "How to use jasmine?" questions and a history of other solutions on the jasmine-js group. We try to keep jasmine's github issues list focused on bugs and feature requests for jasmine itself. Additionally, your comment has nothing to do with the issue to which you are replying. If you have an issue to report, please create a new issue. Thanks for using Jasmine! |
This testing approach might provide a short-term or case-by-case alternative to changing the Jasmine framework: |
@slackersoft With the latest native async support in Jasmine, I can simply write an
which is pretty cool. But, in this case, we are not handling any errors.. How, can I do error handling here so that I can log my error messages to the console which would help me in debugging? Could you give me any pointers? |
If you use the Thanks for using Jasmine! |
@slackersoft True, I am actually looking for a way to use Before the native async support, I used to use my own custom
Now, I removed this
The same spec used to look like follows with my custom
|
@applecool if you would like to see more/different information reported when a rejected promise causes a spec to fail, please open a new issue with the additional information you'd like to see. A rejection that comes through with an Thanks for using Jasmine! |
@slackersoft I will open an issue. Thank you. I was wondering if you could just point me in a right direction here: I am trying to override the
I also wanted to know if I am on the correct path of overwriting the Thank you. |
I'm getting bit really hard by these issues: - jestjs/jest#2713 - jasmine/jasmine#577 - jasmine/jasmine#529
I'm getting bit really hard by these issues: - jestjs/jest#2713 - jasmine/jasmine#577 - jasmine/jasmine#529
Thanks for fixing this! Is there a matcher for these async errors? |
Yes and no. It depends on what you're trying to accomplish. If you're trying to verify that your async code reports errors by rejecting a promise and doesn't trigger a global error, then you might use On the other hand, if you want your test to pass when a global error occurs and fail when it doesn't, then there's nothing built-in for that. I've seen some people spy on |
When an error is thrown from asynchronous code, Jasmine currently has no way of knowing that it happened, skipping subsequent stages (e.g. "it" following error in "beforeEach") and reporting a trace.
As a workaround, I have written helper code to catch and record the error from a function execution so that it can be re-thrown from an "afterEach" block. This solution at least gives a failure and a stack trace, but still leaves a lot to be desired.
For my partial workaround, see the "asyncStep" and "getCaptureAsyncError" functions in https://github.com/stevecj/headway/blob/master/spec/support/userContextExt.js . To see how those are used, see https://github.com/stevecj/headway/blob/master/spec/indexedDbAdapterSpec.js .
The text was updated successfully, but these errors were encountered: