Skip to content
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

Handle async errors #4016

Merged
merged 10 commits into from
Aug 24, 2017
Merged

Handle async errors #4016

merged 10 commits into from
Aug 24, 2017

Conversation

dignifiedquire
Copy link
Contributor

The goal is to resolve the issues in #2059.

General ideas are

  1. Attach uncaughtException and unhandledRejection handlers around the test suite execution
  • if something is caught
    • during a spec run: fail the spec
    • outside a spec, inside a suite: fail the suite
  1. Add support for the signature
test('my test', done => {
  done(new Error('fail'));
});

I have gotten 2. working, but ran into an issue with 1. I am able to catch the exceptions and set the errors from Env.js, but there is currently no way to cancel a spec run. To enable this I would need to change queue_runner.js such that it allows for cancellation. Before I go on I would like to get some feedback on this.

PS: This is the same approach that mocha currently takes to handle these: https://github.com/mochajs/mocha/blob/master/lib/runner.js#L681

@dignifiedquire
Copy link
Contributor Author

I have added some basic cancelation handling into the queue_runner which makes the test in promise_it.test.js fail as expected now.

@daviddias
Copy link

Hi there! Really looking for this feature in jest. Any hopes of getting this merged soon? Thank you!

@dignifiedquire
Copy link
Contributor Author

This should be ready, I am not sure why the CI is failing yarn test passes fine locally for me

@aaronabramov
Copy link
Contributor

hey @wtgtybhertgeghgtwtg! do you mind giving this a look? :)

@wtgtybhertgeghgtwtg
Copy link
Contributor

It looks like the issue is with resolving jest-runner. I can't seem to find any other issues like this, although jest-runner is only like six days old.

@dignifiedquire
Copy link
Contributor Author

@wtgtybhertgeghgtwtg any pointers on how I can help debug this?

@wtgtybhertgeghgtwtg
Copy link
Contributor

Nothing particularly helpful.

@dignifiedquire
Copy link
Contributor Author

dignifiedquire commented Aug 22, 2017

@dignifiedquire dignifiedquire force-pushed the fix/async-tests branch 2 times, most recently from c4dc4b5 to cd872fa Compare August 22, 2017 21:32
@dignifiedquire
Copy link
Contributor Author

@wtgtybhertgeghgtwtg circle is happy now :) appveyor fail seems unrelated

@dignifiedquire
Copy link
Contributor Author

@aaronabramov @wtgtybhertgeghgtwtg any more feedback? I would really like to see this merged soon as it is currently blocking me from migrating a bunch of projects over to jest.

@@ -37,12 +37,6 @@ function formatCoverageError(error, filename: Path): SerializableError {
};
}

// Make sure uncaught errors are logged before we exit.
process.on('uncaughtException', err => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot remove this, this is not related to tests.

@@ -12,12 +12,6 @@ import type {GlobalConfig, Path, ProjectConfig} from 'types/Config';
import type {SerializableError, TestResult} from 'types/TestResult';
import type {RawModuleMap} from 'types/HasteMap';

// Make sure uncaught errors are logged before we exit.
process.on('uncaughtException', err => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to keep this one. The workers don't exclusively run Jasmine, and uncaught errors outside of Jasmine (like when no test is run) need to keep working. Is there a concept of "bubbling" in node's exception handling? I'm fine if this handler is disabled while the other exception handler is active, but at least one of the two needs to always be active.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried making it work with these handlers in place, but the issue was that as soon as they are here I am unable to capture the exceptions in Jasmine. (Same for the one in coverage_worker`). Is there an easy way to detect what is currently being run, so I can switch between those?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I would prefer some sort of nesting, where this handle here is the parent and the other handler you install is the child. Not sure how to make it work elegantly right now :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have pushed a version that removes and restores the listeners from jasmine, which seems to work well.

@@ -57,10 +71,16 @@ async function queueRunner(options: Options) {
);
};

return options.queueableFns.reduce(
const res = options.queueableFns.reduce(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"result"

@cpojer
Copy link
Member

cpojer commented Aug 24, 2017

I was quite heavily against this approach, but I like the solution we ended up with because it captures all uncaught exceptions without overwriting setTimeout etc. for every single test, and something we should do regardless. Good work.

I'll spend some time testing this soon and giving it a thorough review, but we'll try to get this into Jest 21.

@cpojer cpojer mentioned this pull request Aug 24, 2017
6 tasks
@cpojer cpojer merged commit 2b7c97d into jestjs:master Aug 24, 2017
@cpojer
Copy link
Member

cpojer commented Aug 24, 2017

This looks solid, so I'm went ahead and merged it, but I'm somewhat scared that this is going to mess everything up in some subtle way and we'll find out in a month or two ;) It's a scary change, but thank you @dignifiedquire for proposing it and making a PR.

If you'd like to catch errors thrown in timer functions, we do have FakeTimers which defines the timers. They are off by default, but what you could do, if you'd like to send another PR, is to change it so that setTimeout and others in a vm context (Every test file is run in isolation) is wrapped with a try-catch block that will catch errors and fail the test. What do you think?

@dignifiedquire
Copy link
Contributor Author

dignifiedquire commented Aug 24, 2017

🎉 great to see this merged, I hope the subtle breakages are not too bad ;)

Regarding the timers, thanks for the pointer I'll take a look in the next days and see if I can figure it out.

@cpojer
Copy link
Member

cpojer commented Aug 24, 2017

Published jest@test (Jest 21 beta) so you can give this a try. Also enjoy a substantially faster Jest startup.

@dignifiedquire dignifiedquire deleted the fix/async-tests branch August 24, 2017 21:29
@dignifiedquire
Copy link
Contributor Author

@cpojer not sure that publish (or my install) works as expected. I am not getting any jest binary anymore after installing. If I run ls node_modules/jest I get this:

ls node_modules/jest
browser.spec.js fixtures        test.spec.js
config          lint.spec.js    utils.spec.js

not even listing a package.json

@cpojer
Copy link
Member

cpojer commented Aug 24, 2017

@dignifiedquire not sure what you did, but you definitely didn't install Jest. yarn add jest@test works just fine for me:

screen shot 2017-08-24 at 10 53 38 pm

@dignifiedquire
Copy link
Contributor Author

I think I hit a bug/feature in yarn, running yarn add jest@test with a folder called test just added that folder as a module Oo

@cpojer
Copy link
Member

cpojer commented Aug 24, 2017

ohhh that's possible…

@jamesreggio
Copy link

Perhaps this is the wrong place to comment, but I'm fairly concerned about the change in semantics around the asynchronous done function. In my opinion, it's a major breaking change.

If the pre-21 done function ignores arguments, it's simple to supply a bare done reference as the recipient of any callback without concern about the arguments passed to the callback. As soon as it begins interpreting arguments as an error condition, all kinds of existing tests are going to break.

For example, the event argument received by the onPress callback will change this test from passing to failing.

it('fires the onPress callback', done => {
  const wrapper = shallow(<TouchableOpacity onPress={done} />);
  wrapper.find('TouchableOpacity').simulate('press');
});

I realize that interpreting arguments to done makes Jest more consistent with other JS testing frameworks, but I worry that the time for this convergence has sailed, especially since Jest offers done.fail as the preferred method for explicitly failing a test.

Sorry about the drive-by FUD. Just thought I'd mention it because this has become a subject of discussion internally.

@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants