Jest: The `unhandledRejection` handler is not testable anymore.

Created on 20 Feb 2018  ยท  16Comments  ยท  Source: facebook/jest

Do you want to request a _feature_ or report a _bug_?

Regression

What is the current behavior?

Current versions of jest don't allow testing unhandledRejections. The following test will never succeed:

const foo = require(".");

describe("foo", () => {
  test("bar", done => {
    process.removeAllListeners("unhandledRejection");
    process.on("unhandledRejection", function(error) {
      process.removeAllListeners("unhandledRejection");
      expect(error).toBeInstanceOf(Error);
      done();
    });

    foo();
  });
});

If the current behavior is a bug, please provide the steps to reproduce and
either a repl.it demo through https://repl.it/languages/jest or a minimal
repository on GitHub that we can yarn install and yarn test.

I made a repository with two commits with different jest versions showing that it works with an older version but not anymore with the current one. The README describes the repro steps in detail.

What is the expected behavior?

It should be possible to test unhandledRejection and uncaughtExceptions.

Btw I'm well aware that this is a case of https://xkcd.com/1172/ and that we could refactor the code to not rely on unhandledRejection for error reporting of unknown errors that happen. But it's actually really convenient to use the unhandledRejection handler to report to rollbar and shutdown the process orderly.

Please provide your exact Jest configuration and mention your Jest, node,
yarn/npm version and operating system.

OS: Mac 10.12.6
Node: v8.9.4
Yarn: 1.3.2

Regression Needs Triage

Most helpful comment

Same problem here... trying to test my error handling (logging, Sentry reporting). It works fine in my other app that uses mocha for its tests, but Jest just won't let me do it.

All 16 comments

Not to dredge up the dead but I have a similar issue with testing unhandledrejection. Consider

window.addEventListener('unhandledrejection', event => this.onUnhandledRejection(event), {
    passive: true,
})

This code should take any unhandled promise rejection and work with it.

It works in browser but I think jsdom or jest doesn't support it. For now I have the line ignored but it would be nice to have.

OS: Windows 10
Node: 10.7.0
NPM: 6.0.0

Confirming the bug with a simple example:

test('catches unhandled rejections', async () => {
  const errorHandler = jest.fn();
  const error = new Error('mock error');
  process.on('unhandledRejection', err => errorHandler(err))
  await Promise.reject(error);
  expect(errorHandler).toHaveBeenCalledWith(error);
});

will give you this

โ— catches unhandled rejections

mock error

  13 |
  14 | test('catches unhandled rejections', async () => {
> 15 |   const error = new Error('mock error');
     |                 ^
  16 |   const errorHandler = jest.fn();
  17 |   process.on('unhandledRejection', err => errorHandler(err))
  18 |   await Promise.reject(error);

  at Object.<anonymous>.test (test/bin.test.js:15:17)

OS: macOs 10.13.6
Node: v8.11.4 (LTS)
Yarn: 1.9.4

I also took this to StackOverflow: https://stackoverflow.com/questions/52493145/how-to-test-a-unhandledrejection-uncaughtexception-handler-with-jest

Has anyone found a workaround for this issue?

Confirmed that this breaks testing functions that throw uncaught exceptions, too: https://repl.it/repls/FreeFluffyAdministration

This should be resolved because unhandledPromiseRejection might make random subsequent test fail.

Any update on this issue yet?

Same problem here... trying to test my error handling (logging, Sentry reporting). It works fine in my other app that uses mocha for its tests, but Jest just won't let me do it.

+1

+1

+1

+1

Any updates on this? This would be needed to test error cases where error gets thrown after user response has already been sent.

Yes, I want to ensure there _is_ a unhandledPromiseRejection and I found I can't do this in Jest.

I can confirm this issue still happens for 'uncaughtException' as well. Currently, I don't have any workaround, other than rewrite production code to emit errors instead of throwing them, and then catch with this.on('error')

This happens because jest mocks the global process object, which prevents access to the real unhandledRejection event. I couldn't find any way to circumvent the mock or register an unhandledRejection event for a single test.

This prevents making the test fail when there is an unhandled promise in the code. It is a problem because developers are not aware there is something to fix since the test is marked successful. If there is only one test we could ask the dev to check the "UnhandledPromiseRejectionWarning" is not present in the logs before they merge, the problem is there are many tests and those warnings might be easily unseen as long as the tests are green. We then end up with many unhandled promises in the tests that might disrupt the execution of tests in our CI, and also many unhandled promises unfixed in the code, it is really bad.

After some tests, it is not possible to listen to the process events because it is not the real one (why?), we can't exploit its stdout either, the stdout of the test can't be piped :(. Even if we could exploit stdout, what we need is to fail the test to prevent the merge, so it should be done in the jest run. I haven't found any workaround. This was possible to fix in jest 24 by listening to the process "unhandledRejection" event but not possible in jest 26 because process is not the real one.

Please help?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kgowru picture kgowru  ยท  3Comments

Secretmapper picture Secretmapper  ยท  3Comments

mmcgahan picture mmcgahan  ยท  3Comments

paularmstrong picture paularmstrong  ยท  3Comments

withinboredom picture withinboredom  ยท  3Comments