I'm writing an integration test for a component that should redirect to a specific path depending on the response from an asynchronous (thunk) redux action.
This is a simplified version of my component:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
redirect: false
}
this.props.dispatch(asyncThunkAction())
.then( () => this.setState({redirec: true}) )
.catch( (err) => console.log('action failed') )
}
...
render() {
if (this.state.redirect) {
return <Redirect to='/whocares' />
}
...
}
}
function mapStateToProps(state) {
return {
...
};
}
export default connect(mapStateToProps)(MyComponent);
I want to write a test that asserts that the component redirected to the expected path.
I am using this technique for inspecting the actual redirection path (It's not perfect but it's not the focus of this question).
The place where I am stuck is the state change in the .then() following the redux/thunk action. Because it's a promise, the redirect happens after my expect statement, so I have not been able to test that.
Here's what my test looks like:
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
test('redirects after thunk action', () => {
const redirectUrl = '/whocares'
const data = {};
jest.mock('../actions');
act(() => {
ReactDOM.render(
<TestRouter
ComponentWithRedirection={<MyComponent store={mockStore(data)} />}
RedirectUrl={redirectUrl}
/>,
container);
});
expect(container.innerHTML).toEqual(
expect.stringContaining(redirectUrl)
)
})
My TestRouter just prints the anticipated redirect URL into the DOM. (Check out the link above for a full explanation of this hack.) So right now instead of hitting the expected route, my test (correctly) identifies the loading screen that appears while the thunk action is in progress.
I think the right way to do this is to mock the response from asyncThunkAction so that it returns a resolved promise with matching data, but so far I have not been able to figure out how to do that. I followed the Jest documentation on manual mocks and created the corresponding mock file:
// __mocks__/actions.js
const asyncThunkAction = function(){
return Promise.resolve({foo: 'bar'});
};
export { asyncThunkAction };
...but my test still "sees" the loading state. I don't even think it's looking at my mocked file/action.
What is the right way to do this?