Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a component using react-redux hooks?

I have a simple Todo component that utilizes react-redux hooks that I'm testing using enzyme but I'm getting either an error or an empty object with a shallow render as noted below.

What is the correct way to test components using hooks from react-redux?

Todos.js

const Todos = () => {   const { todos } = useSelector(state => state);    return (     <ul>       {todos.map(todo => (         <li key={todo.id}>{todo.title}</li>       ))}     </ul>   ); }; 

Todos.test.js v1

...  it('renders without crashing', () => {   const wrapper = shallow(<Todos />);   expect(wrapper).toMatchSnapshot(); });  it('should render a ul', () => {   const wrapper = shallow(<Todos />);   expect(wrapper.find('ul').length).toBe(1); }); 

v1 Error:

... Invariant Violation: could not find react-redux context value;  please ensure the component is wrapped in a <Provider> ... 

Todos.test.js v2

... // imported Provider from react-redux   it('renders without crashing', () => {   const wrapper = shallow(     <Provider store={store}>       <Todos />     </Provider>,   );   expect(wrapper).toMatchSnapshot(); });  it('should render a ul', () => {   const wrapper = shallow(<Provider store={store}><Todos /></Provider>);   expect(wrapper.find('ul').length).toBe(1); }); 

v2 tests also fail since wrapper is the <Provider> and calling dive() on wrapper will return the same error as v1.

Thanks in advance for your help!

like image 495
crowns4days Avatar asked Jun 30 '19 18:06

crowns4days


People also ask

How do I test Redux application?

Redux can be tested with any test runner, since it's just plain JavaScript. One common option is Jest, a widely used test runner that comes with Create-React-App, and is used by the Redux library repos. If you're using Vite to build your project, you may be using Vitest as your test runner.

How do you test React hooks?

If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote. To reduce the boilerplate, we recommend using React Testing Library which is designed to encourage writing tests that use your components as the end users do.


2 Answers

To mock useSelector use can do this

import * as redux from 'react-redux'  const spy = jest.spyOn(redux, 'useSelector') spy.mockReturnValue({ username:'test' }) 
like image 162
Kriti Avatar answered Sep 28 '22 01:09

Kriti


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)   }) }) 
like image 37
abidibo Avatar answered Sep 28 '22 02:09

abidibo