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

thenReject causes UnhandledPromiseRejectionWarning #238

Closed
iLikeKoffee opened this issue Jun 23, 2021 · 5 comments
Closed

thenReject causes UnhandledPromiseRejectionWarning #238

iLikeKoffee opened this issue Jun 23, 2021 · 5 comments

Comments

@iLikeKoffee
Copy link

Hello. First of all - thank you for awesome tool! I enjoy working with it every time!

There is some trouble with testing service rejections. See:

    test('rejection', () => {
        const UsersService = stubUsersService();
        when(UsersService.deleteUser(users[2]._id))
            .thenReject(new UserDeletionError(new OfflineError())).once();
    })

this results

(node:96407) UnhandledPromiseRejectionWarning: common-offline
(Use `node --trace-warnings ...` to show where the warning was created)
(node:96407) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:96407) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

And sometimes it causes test failures (jest + new versions react testing library has stricter promise rejection policies, if there is a rejected promise in queue - test fails)
So, i have to do something like this:

        /* try-catch is a workaround for unhandled promise rejections in strong-mock */
        try{
            await when(UsersService.deleteUser(users[2]._id)).thenReject(new UserDeletionError(new OfflineError())).once();
        } catch (e){}

And this helps me to get my tests passed.

I will be glad to provide any needed assistance to fix that if needed.

Have a nice day!

@iLikeKoffee
Copy link
Author

Looks like swallowing errors in thenReject can be a working solution, something like this, but I'm not sure this is a good one, and this should be discussed.

 thenReject: function (errorOrMessage) {
            const promise = Promise.reject(getError(errorOrMessage))
            promise.catch((error) => {/* this error is swallowed to prevent failing tests in strict environment */})
            return finishPendingExpectation(promise, pendingExpectation);
        }

@NiGhTTraX
Copy link
Owner

Hey @iLikeKoffee, happy to hear you'r finding the lib useful so far :)

In your test example above you're mocking deleteUser to throw, but then no code calls the instance method to catch the exception, so the unhandled rejection warning is expected, albeit a bit confusing. I don't know if you maybe simplified the example too much, but there should be some code that receives instance(UsersService), calls deleteUser on it and has a catch handler.

I'm actually in the process of making thenReject lazy so it creates the promise only when the corresponding mock instance property is accessed. This will turn the unhandled rejection warning into an UnmetExpectation error in your example (provided that you have a verify or verifyAll call at the end of your test).

I'll leave the issue open until I finish the above, but just wanted to clarify that your test example is supposed to fail because the expectation is not met.

@iLikeKoffee
Copy link
Author

In your test example above you're mocking deleteUser to throw, but then no code calls the instance method to catch the exception, so the unhandled rejection warning is expected, albeit a bit confusing. I don't know if you maybe simplified the example too much, but there should be some code that receives instance(UsersService), calls deleteUser on it and has a catch handler.

Yes, my code has rejection handler. But Promise.reject() adds rejected promise into queue and react test utilities(and @testing-library/react accordingly) act(() => {....}) fails, because there is uncaught promise rejection even BEFORE userService.deleteUser(...) is called. I suppose there is some kind of dark magic under the hood 😀.

As far as I understand mechanics of act - it fails if uncaught rejected promise exists in global scope, and rejected promise is created in thenReject(...) call, so I strongly believe that lazy promise creation will do the trick and problem will be solved.

Thank you for quick response!
Have a nice day!

@NiGhTTraX
Copy link
Owner

Hey @iLikeKoffee, this should now be fixed in 7.1.0.

@iLikeKoffee
Copy link
Author

Sorry, I have written comment, and forgot to submit it a year ago. Thank you so much, works like a charm!

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

No branches or pull requests

2 participants