How to test a component using react-redux hooks?
I could test a component which uses redux hooks using enzyme mount facility and providing a mocked store to the Provider:
Component
import React from 'react';import AppRouter from './Router'import { useDispatch, useSelector } from 'react-redux'import StartupActions from './Redux/Startup'import Startup from './Components/Startup'import './App.css';// This is the main component, it includes the router which manages// routing to different views.// This is also the right place to declare components which should be// displayed everywhere, i.e. sockets, services,...function App () { const dispatch = useDispatch() const startupComplete = useSelector(state => state.startup.complete) if (!startupComplete) { setTimeout(() => dispatch(StartupActions.startup()), 1000) } return ( <div className="app"> {startupComplete ? <AppRouter /> : <Startup />} </div> );}export default App;
Test
import React from 'react';import {Provider} from 'react-redux'import { mount, shallow } from 'enzyme'import configureMockStore from 'redux-mock-store'import thunk from 'redux-thunk';import App from '../App';const mockStore = configureMockStore([thunk]);describe('App', () => { it('should render a startup component if startup is not complete', () => { const store = mockStore({ startup: { complete: false } }); const wrapper = mount( <Provider store={store}> <App /> </Provider> ) expect(wrapper.find('Startup').length).toEqual(1) })})
To mock useSelector use can do this
import * as redux from 'react-redux'const spy = jest.spyOn(redux, 'useSelector')spy.mockReturnValue({ username:'test' })
There is another way than @abidibo if you use a function selector defined in another file. You can mock useSelector
and your selector function, and then use shallow
from enzyme:
Component
import * as React from 'react';import { useSelector } from 'react-redux';import Spinner from './Spinner';import Button from './Button ';import { getIsSpinnerDisplayed } from './selectors';const Example = () => { const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed); return isSpinnerDisplayed ? <Spinner /> : <Button />;};export default Example;
Selectors
export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;
Test
import * as React from 'react';import { shallow } from 'enzyme';import Example from './Example';import Button from './Button ';import { getIsSpinnerDisplayed } from './selectors';jest.mock('react-redux', () => ({ useSelector: jest.fn(fn => fn()),}));jest.mock('./selectors');describe('Example', () => { it('should render Button if getIsSpinnerDisplayed returns false', () => { getIsSpinnerDisplayed.mockReturnValue(false); const wrapper = shallow(<Example />); expect(wrapper.find(Button).exists()).toBe(true); });});
It may be a little bit hacky, but it works well for me :)