Description
We're getting an error with one of our tests in our CRA app. Our test looks a bit like the following:
import React from 'react'
import { shallow } from 'enzyme'
const flushPromises = () => new Promise(resolve => setImmediate(resolve))
const fetchTheData = jest.fn()
class MyContainerComponent extends React.Component {
state = { error: null }
async componentDidMount() {
try {
await fetchTheData()
} catch (e) {
this.setState({ error: 'There was a problem' })
throw e // rethrow so it gets handled by a generic unhandled promise rejection handler (e.g. Sentry)
}
}
render() {
return <p>{this.state.error}</p>
}
}
it('should handle errors calling the API', async () => {
fetchTheData.mockImplementation(() => Promise.reject(new Error('something bad happened')))
const component = shallow(<MyContainerComponent />)
await flushPromises()
expect(component.update()).toIncludeText('There was a problem')
})
However, it blows up on npm test
with:
RUNS src/App.test.js
/Users/matt/misc-repos/promise-rejection-oddity/node_modules/react-scripts/scripts/test.js:20
throw err;
^
Error: something bad happened
at fetchTheData.mockImplementation (/Users/matt/misc-repos/promise-rejection-oddity/src/App.test.js:26:56)
at mockConstructor (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/jest-mock/build/index.js:288:37)
at MyContainerComponent.componentDidMount (/Users/matt/misc-repos/promise-rejection-oddity/src/App.test.js:13:13)
at /Users/matt/misc-repos/promise-rejection-oddity/node_modules/enzyme/build/ShallowWrapper.js:126:20
at Object.batchedUpdates (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:342:22)
at new ShallowWrapper (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/enzyme/build/ShallowWrapper.js:125:24)
at shallow (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/enzyme/build/shallow.js:19:10)
at Object.<anonymous>.it (/Users/matt/misc-repos/promise-rejection-oddity/src/App.test.js:28:41)
at Object.asyncFn (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/jest-jasmine2/build/jasmine-async.js:68:30)
at resolve (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/jest-jasmine2/build/queueRunner.js:38:12)
at new Promise (<anonymous>)
at mapper (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/jest-jasmine2/build/queueRunner.js:31:21)
at Promise.resolve.then.el (/Users/matt/misc-repos/promise-rejection-oddity/node_modules/p-map/index.js:46:16)
npm ERR! Test failed. See above for more details.
This behaviour appears to be because there is an unhandled rejection, and in react-scripts/scripts/test.js
:
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
So, I guess I wanted to understand whether what we're trying to do in our test is bad -- we have an unhandled rejection, but that's intentional, and not a problem in the browser environment (we have a global error handler that will deal with it). Is CRA being overly enthusiastic in causing the script to crash in these cases? Should we be dealing with things in a different way?
The other oddity is that most of the time, when all the tests in our actual app's test suite are run together, the test passes. It's only when run in isolation that we trigger the unhandledRejection
event listener and the script exits. Any ideas on why that might be the case?