Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking Redux store when testing React components?

I'm using React and Redux. I have a component which loads ChildComponent and depending on Redux's state will also load MainComponent

    const ChooseIndex = ({ appInitMount }) => {
      return (
        <>
          <ChildComponent />
          {!appInitMount && <MainComponent />}
        </>
      );
    };


    const mapStateToProps = ({ main }) => {
      return {
        appInitMount: main.appInitMount
      };
    };

    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(ChooseIndex);

I'm trying to write a test to check that ChildComponent is loaded:

    import React from "react";
    import { render } from "react-testing-library";
    import ChooseIndex from "../choose-index";

    test("ChooseIndex should call ChildComponent", () => {
      const wrapper = render(
        <ChooseIndex />
      );
    });

I get this error:

Error: Uncaught [Invariant Violation: Could not find "store" in either the context or props of "Connect(ChooseIndex)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(ChooseIndex)".]

Should I mock Redux by passing an object literal to ChooseIndex? Or should I create a Redux store (as my real application does) for every test?

like image 305
Evanss Avatar asked Nov 07 '22 00:11

Evanss


2 Answers

Try to render your component like this:

render(
  <Provider store={store}>
    <ChooseIndex />
  </Provider>
)

And pass the actual store you use in your app. In this way, you're testing the real logic that you'll use in production. You also don't care what actions get dispatched and what's in the state. You look at what gets rendered and interact with the UI—which is what matters in the end.

Separating the component from Redux and testing the two in isolation is against the whole point of react-testing-library. You want to test your app as a real user would.

like image 173
Giorgio Polvara - Gpx Avatar answered Nov 15 '22 05:11

Giorgio Polvara - Gpx


If you check out the writing tests section of the redux docs, there is an example of testing a connected component.

when you import it [A redux connected component], you're actually holding the wrapper component returned by connect(), and not the App component itself. If you want to test its interaction with Redux, this is good news: you can wrap it in a with a store created specifically for this unit test. But sometimes you want to test just the rendering of the component, without a Redux store.

In order to be able to test the App component itself without having to deal with the decorator, we recommend you to also export the undecorated component

As with most unit tests, you really want to be testing your components, and not that redux is working correctly. So the solution for you is to export both the component and the connected component, while only testing the component itself, and providing whatever props redux is passing to your component.

import { connect } from 'react-redux'

// Use named export for unconnected component (for tests)
export class App extends Component {
  /* ... */
}

// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)
like image 38
Wolfie Avatar answered Nov 15 '22 07:11

Wolfie