jest-mock-axios icon indicating copy to clipboard operation
jest-mock-axios copied to clipboard

UnhandledPromiseRejection when returing `Promise.reject` on interceptor

Open ashalfarhan opened this issue 2 years ago • 6 comments

I'm trying to test my interceptor logic, whether calling the error reporter (like Sentry), showing toast error, and resetting the auth state if we received a 401 response from our server. The problem that we're facing is that we got the following error every time we ran the test:

[UnhandledPromiseRejection: 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(). The promise rejected with the reason "AxiosError".] 
{
  code: 'ERR_UNHANDLED_REJECTION'
}

Based on Interceptors Docs we need to return a rejected promise on the second parameter (onRejected) for the interceptor, but when I remove the Promise.reject calls (just returning the error), the test successfully ran.

But that turns out to break my app.

Additional info that might help

  • Stackblitz to reproduce https://stackblitz.com/edit/node-wsmxdh?file=index.test.ts

Any idea how I test my interceptor logic without breaking my app? Thanks in advance!

ashalfarhan avatar Aug 31 '22 15:08 ashalfarhan

Hi,

thanks for raising this issue. You're right, response interceptors returning a promise are not correctly handled at the moment. I'll fix this.

kingjan1999 avatar Sep 01 '22 15:09 kingjan1999

Hi,

I published 4.7.0-beta on npm. This should fix the UnhandledPromiseRejection at least and make the test work. Can you install this version and try if it works?

This still does not implement correct interceptor behavior, as the result of the onRejected handler is discarded in any case. However, for the moment this might be enough.

kingjan1999 avatar Sep 01 '22 17:09 kingjan1999

Hi @kingjan1999. I've installed the 4.7.0-beta and it works. Thanks!

ashalfarhan avatar Sep 02 '22 01:09 ashalfarhan

Hello, I am also trying to test response interceptors. My test is expecting the function-under-test to throw an error, which is what I believe Promise.reject normally does, and it is failing because no error is being thrown. This is happening with 4.7.0-beta

If I'm testing it incorrectly, please let me know, but here is what I'm doing:

    it('will throw unauthorized if the status is 401', async () => {
      await expect(() => {
        const promise = service.getTheThing()
        mockAxios.mockError({ response: { status: 401, data: {} }})
        return promise
      }).rejects.toThrow(UnauthorizedError)
    })

The interceptors:

    axios.interceptors.response.use((response) => {
      return response
    }, (error: AxiosError) => {
      if (error?.response?.status) {
        // This function just returns the appropriate error object to be thrown by Promise.reject()
        return Promise.reject(this.checkExceptionForStatus(error))
      }

      return Promise.reject(error)
    })
    

rosstroha avatar Sep 06 '22 18:09 rosstroha

@rosstroha I think you stumbled about the behavior I described above with "interceptors are not corrected properly".

The current implementation in 4.7.0-beta just avoids the error being unhandled completely, but it does not handle it properly whatsoever. I'll fix this before releasing 4.7.0 , once I've found out why this isn't working at the moment.

kingjan1999 avatar Sep 06 '22 20:09 kingjan1999

@rosstroha I think you stumbled about the behavior I described above with "interceptors are not corrected properly".

The current implementation in 4.7.0-beta just avoids the error being unhandled completely, but it does not handle it properly whatsoever. I'll fix this before releasing 4.7.0 , once I've found out why this isn't working at the moment.

Fair enough :) Thank you @kingjan1999!

rosstroha avatar Sep 07 '22 14:09 rosstroha