Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing an asynchronous throw error in a Promise catch with Jest

I have the following code that I'd like to test.

const Component: React.FC = () => {
   const handleSubmit = (action) => {
       doSomethingAsynchronous()
           .then(() => /* something on success */)
           .catch((err) => {
               // Display the error message
               action();

               // Rethrow the exception so it can be handled up the chain
               throw err;
           })
   }

   return <Form onSubmit={handleSubmit} />;
}

This code performs a simple asynchronous action that fails or resolves. On a failure, the component is re-rendered to show an error message, and the error is rethrown to log to the console/our logging system and for parent components to deal with.

The problem comes when I am attempting to test the error handling behaviour to ensure that the error messages are being set. Simple testing such as:

describe('Component', () => {
   it('handles an error', async () => {
       // Setup
       const mockAction = jest.fn();
       const render = shallowRender(<Component />);
       submissionHandler = render.find(Component).invoke('onSubmit');

       // Act
       submissionHandler(mockAction);
       await () => new Promise(setImmediate); // To wait for promise execution

       // Assert
       expect(mockAction).toHaveBeenCalled();
   })
})

Results in Jest failing the test as an error has been thrown in the test by the component, inside the catch block (as expected). However, my attempts to suppress this also result in the same error being thrown and failing the test.

try {
    // Act
    submissionHandler(mockAction);
    await () => new Promise(setImmediate); // To wait for promise execution
} catch (e) {}

I also tried using expects().toThrow(), but this instead returns the jest error Received function did not throw. I assume this is because due to the promise the execution is no longer in the same function scope, so isn't being recognised by Jest as originating from that function?

await expect(async () => {
   submissionHandler(mockAction);
   await () => new Promise(setImmediate);
}).toThrow();

Does anyone know the best way to test this? I'm aware I can cheat by making onSubmit return my promise here and catching the exception there, but I'd avoid doing that to stop my function returning for testing purposes.

like image 838
James Paterson Avatar asked Oct 22 '25 00:10

James Paterson


1 Answers

You need to unpack your errors from your promise with .rejects

try this:

import { spyOn } from 'jest-mock';
...

it("should error", async() => {
  spyOn(console, 'error'); #removes error from output
  await expect( yourAsyncMethod() ).rejects.toThrow() # .rejects unpacks errors from promises
}
like image 89
Codeninja Avatar answered Oct 23 '25 14:10

Codeninja