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

Unhandled async errors crash Jest. #2059

Closed
cpojer opened this issue Nov 6, 2016 · 45 comments
Closed

Unhandled async errors crash Jest. #2059

cpojer opened this issue Nov 6, 2016 · 45 comments
Labels

Comments

@cpojer
Copy link
Contributor

@cpojer cpojer commented Nov 6, 2016

On master, I changed one of the tests in jest-haste-map from toBeDefined() or something to not.toBeDefined(). It would then go on to crash Jest:

[cpojer: ~/Projects/jest (master)]$ jest "haste-map.*index"

 RUNS  packages/jest-haste-map/src/__tests__/index-test.js

/Users/cpojer/Projects/jest/packages/jest-jasmine2/node_modules/jest-matchers/build/index.js:110
        throw error;
        ^
Error: expect(received).toBeNull()

Expected value to be null, instead received
  undefined
    at HasteMap.hasteMap.once (/Users/cpojer/Projects/jest/packages/jest-haste-map/src/__tests__/index-test.js:685:62)
    at HasteMap.g (events.js:291:16)
    at emitOne (events.js:96:13)
    at HasteMap.emit (events.js:188:7)
    at Timeout.emitChange (/Users/cpojer/Projects/jest/packages/jest-haste-map/src/index.js:562:14)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5)

@dmitriiabramov what have we done?

@cpojer
Copy link
Contributor Author

@cpojer cpojer commented Nov 7, 2016

Oh, it might have been because I didn't return the promise but instead am using Jasmine's async work. Nevertheless, we should hook up an unhandled promise handler in Jest.

@cpojer cpojer changed the title Thrown promises crash Jest Unhandled async errors crash Jest. Nov 29, 2016
@mweststrate
Copy link
Contributor

@mweststrate mweststrate commented Nov 29, 2016

Currently we use in our tests a utility to work around this in a quite cumbersome way:

/**
 * In async tests, JEST will die (in watch mode) if an exception is thrown from a callback. This utility will catch
 * the errors instead and report the test as failed in these case *
 *
 * @param {jest.DoneCallback} done
 * @param {T} callback
 * @returns {T}
 */
export function catchErrors<T extends Function>(done: jest.DoneCallback, callback: T): T {
	return function() {
		try {
			callback.apply(this, arguments)
		} catch (e) {
			done.fail(e)
		}
	} as any as T
}

which then can be used as follows:

describe("suite", () => {
	it("should handle async exceptions", (done) => {
                setTimeout(catchErrors(done, (err, res) => {
                        throw "Catched by catchErrors so that our tests properly fail!"
                        done() 
                }), 100)
        })
})

Any cleaner approach to this would be appreciated!

@mmcgahan
Copy link
Contributor

@mmcgahan mmcgahan commented Dec 1, 2016

this sounds somewhat similar to #1873, where done() is unreachable after failing expect calls in Promises

@julien-f
Copy link

@julien-f julien-f commented Dec 19, 2016

Any news on this?

I also have a repro repo here if that can help.

@lucasconstantino
Copy link

@lucasconstantino lucasconstantino commented Dec 30, 2016

This is some huge drawback for me :( Trying to find a way to circumvent this properly...

@theogravity
Copy link

@theogravity theogravity commented Jan 13, 2017

this is quite frustrating as I have no idea where it's dying

@capaj
Copy link
Contributor

@capaj capaj commented Jan 24, 2017

@mweststrate this should be in the jest core. Seriously, this has been lying here for two months and no one opened a PR yet? 😖

@cpojer
Copy link
Contributor Author

@cpojer cpojer commented Jan 24, 2017

@capaj seems like you are on the hook to make that PR. Jest is an open source project, if you'd like something to be fixed, please start contributing. The attitude you are showing on this issue tracker is not appropriate.

@capaj
Copy link
Contributor

@capaj capaj commented Jan 24, 2017

@cpojer sorry I am just very enthusiastic about my favorite OSS tools. I wasn't aware that displaying negative emotions about negative things is prohibited in jest repo. Next time, I will try to write my comments like a robot, deprived of any emotions.

@cpojer
Copy link
Contributor Author

@cpojer cpojer commented Jan 24, 2017

I'd prefer if you channeled your enthusiasm into code which will help make this project better for everyone or channel it into productive conversation. Negative comments don't help anybody; if that's the only thing you are contributing to this project I'd prefer to see you using a different testing platform.

@capaj
Copy link
Contributor

@capaj capaj commented Jan 24, 2017

@cpojer I beg to disagree, but that's a discussion better suited for some other place/platform

@cpojer
Copy link
Contributor Author

@cpojer cpojer commented Jan 24, 2017

That's ok, we can disagree on this but the Jest project doesn't need your negativity and we won't accept this behavior here.

@jeffbski
Copy link

@jeffbski jeffbski commented Feb 28, 2017

In mocha, the done callback takes an optional error (standard Node.js cb style).

If you call done with a truthy value then it will be used as an error.

promise.then(x => {
  // do something
  done(); // successful
}).catch(err => {
  // do something with error
  done(err); // hand error to test runner
});
@IPWright83
Copy link

@IPWright83 IPWright83 commented Mar 10, 2017

Having a look through this there isn't a reproduction example, so I thought I'd include one. In here the first test will fail reporting

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

while the other two tests correctly reporting back the failed expectation. Correctly works in Jasmine.

describe("Error Reporting", function() {

     it("Async", function(done) {
       setTimeout(function() {
          expect(true).toBe(false);
          done();
       }, 100);
    });

    it("Sync", function() {
        expect(true).toBe(false);
    });

    it("Fake Async", function(done) {
        expect(true).toBe(false);
        done();
    });
});
@evansiroky
Copy link

@evansiroky evansiroky commented Mar 10, 2017

I submitted #1897 that aslo included a reproducible example: https://github.com/evansiroky/jest-exec-bug

evocateur added a commit to evocateur/lerna that referenced this issue Mar 20, 2017
Due to facebook/jest#2059, turns out we need
those try/catch blocks I tried to remove in the previous PR.

Partially reverts lerna#682
@evocateur evocateur mentioned this issue Mar 20, 2017
4 of 9 tasks complete
evocateur added a commit to lerna/lerna that referenced this issue Mar 20, 2017
Due to facebook/jest#2059, turns out we need
those try/catch blocks I tried to remove in the previous PR.

Partially reverts #682
@wilomgfx
Copy link

@wilomgfx wilomgfx commented Mar 27, 2017

@jeffbski indeed thats the most convenient way of doing this! I thought we would be able
to do the same thing with JEST, but instead we have to do : done.fail(ARG)

dignifiedquire added a commit to dignifiedquire/jest that referenced this issue Aug 15, 2017
dignifiedquire added a commit to dignifiedquire/jest that referenced this issue Aug 16, 2017
@dignifiedquire
Copy link
Contributor

@dignifiedquire dignifiedquire commented Aug 16, 2017

@aaronabramov the PR should be ready now, it would be great to get some review on it so we can get this shipped :)

dignifiedquire added a commit to dignifiedquire/jest that referenced this issue Aug 22, 2017
dignifiedquire added a commit to dignifiedquire/jest that referenced this issue Aug 22, 2017
dignifiedquire added a commit to dignifiedquire/jest that referenced this issue Aug 24, 2017
cpojer added a commit that referenced this issue Aug 24, 2017
* wip: start handling async errors

Ref #2059

* Implement basic cancelation

* Improve cancelation

* lint and flow happy, more tests

* snapshot updates

* happy tests

* add tests for before hooks

* log errors if they escape us

* use p-cancelable

* improve based on CR
@cpojer
Copy link
Contributor Author

@cpojer cpojer commented Aug 24, 2017

This is part of Jest 21 thanks to @dignifiedquire. Published jest@test (Jest 21 beta) so you can give this a try. Also enjoy a substantially faster Jest startup.

@cpojer cpojer closed this Aug 24, 2017
midzelis added a commit to midzelis/jest that referenced this issue Aug 30, 2017
* wip: start handling async errors

Ref facebook#2059

* Implement basic cancelation

* Improve cancelation

* lint and flow happy, more tests

* snapshot updates

* happy tests

* add tests for before hooks

* log errors if they escape us

* use p-cancelable

* improve based on CR
@ron-liu
Copy link

@ron-liu ron-liu commented Sep 25, 2017

@dignifiedquire @cpojer I still got timeout for the following test. I am sure I installed version 21.1.0 and I also tried version 21.0.2.
Did I miss anything ?

test.spec.js

it('exception promise', (done) => {
        setTimeout(()=>{
                expect(true).toEqual(false)
                done()
        }, 10)
})

package.json

{
  "name": "testJest",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "jest": "21.1.0"
  },
  "scripts": {
    "test": "jest --debug"
  }
}

image

@kimjoar
Copy link
Contributor

@kimjoar kimjoar commented Sep 26, 2017

Looks like ^ fails when using jsdom, but not when using the node env.

Using node:

$ npx jest --env node
 FAIL  test/index.test.js
  ● exception promise

    expect(received).toEqual(expected)
    
    Expected value to equal:
      false
    Received:
      true
      
      at Timeout.setTimeout [as _onTimeout] (test/index.test.js:3:18)
      at ontimeout (timers.js:469:11)
      at tryOnTimeout (timers.js:304:5)
      at Timer.listOnTimeout (timers.js:264:5)

  ✕ exception promise (18ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.216s, estimated 6s
Ran all test suites.

Using jsdom:

$ npx jest --env jsdom
 FAIL  test/index.test.js (5.114s)
  ● exception promise

    Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
      
      at node_modules/jest-jasmine2/build/queue_runner.js:65:21
      at ontimeout (timers.js:469:11)
      at tryOnTimeout (timers.js:304:5)
      at Timer.listOnTimeout (timers.js:264:5)

  ✕ exception promise (5003ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        5.733s
Ran all test suites.

Minimal repro: https://github.com/kjbekkelund/jest-timeout-issue-jsdom

@ron-liu
Copy link

@ron-liu ron-liu commented Sep 26, 2017

@kjbekkelund yeah, thank you. --env node solved the issue, I did miss this.
Alos check the jest official help .

@SimenB
Copy link
Collaborator

@SimenB SimenB commented Dec 6, 2017

I think that last case might be fixed in #4669

@bobrosoft
Copy link

@bobrosoft bobrosoft commented Dec 11, 2017

@dignifiedquire hey there. In which Jest version that was fixed? Using Jest 21.1.6 and it's still there. My particular case is there https://stackoverflow.com/a/47760009/5086732, crashing if remove try..catch wrapper from there.

@shdwjk
Copy link

@shdwjk shdwjk commented Jan 10, 2018

I'm still seeing this with v20.0.4. In my case with a check inside a redux store reducer.

@bf
Copy link

@bf bf commented Jan 10, 2018

Seems to be a gift that gives on giving...

@SimenB
Copy link
Collaborator

@SimenB SimenB commented Jan 10, 2018

Still happening in 22?

@shdwjk
Copy link

@shdwjk shdwjk commented Jan 10, 2018

Ah, is working in 22.0.5. Great, thanks!

@rawroland
Copy link

@rawroland rawroland commented Jan 16, 2018

I am still experiencing this in 22.1.1 in the following test:

it('replies with the correct message': done => {
  // Initialise a bot with the MS botbuilder framework
  bot.on('send', message => {
     expect(message.text).toEqual('Is everything ok?');
     done();
   });
});
@SimenB
Copy link
Collaborator

@SimenB SimenB commented Jan 16, 2018

Can you provide a repro I can pull down to test?

@rawroland
Copy link

@rawroland rawroland commented Jan 16, 2018

Thanks for the quick reply. Yes, will do so within the next 30 mins.

@rawroland
Copy link

@rawroland rawroland commented Jan 16, 2018

Here is a repo to reproduce the issue: https://github.com/rawroland/async-jest-test.

@SimenB
Copy link
Collaborator

@SimenB SimenB commented Jan 26, 2018

@rawroland that's expected, you're basically seeing #3917.

I'd recommend using promise instead of callback based code, then you don't have to worry about that sort of code flow. E.g.

it('replies with the correct message', async () => {
  // Initialise a bot with the MS botbuilder framework
  const result = await new Promise(resolve => bot.on('send', resolve));

  expect(result.text).toEqual('Is everything ok?');
});
@rawroland
Copy link

@rawroland rawroland commented Feb 1, 2018

Thank you for the information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.