Jon Yardley
Jon Yardley

Reputation: 183

How to test a component with a nested container with React and Redux?

Due to the complexity of the application I am working on I have decided on using a nested redux container rather than passing an action as a prop down to the child components. However, this has proved to be problematic for unit testing when rendering the OuterContainer with jsdom in combination with mocha, chai and sinon.

Here is a contrived example of the view structure:

<OuterContainer>
  <div>
    <InnerContainer />
  </div>
</OuterContainer>

where OuterContainer & InnerContainer are wrapped with connect. e.g.:

export connect(<mapStateToProps>)(<Component>)

When running tests the error I am getting is: Invariant Violation: Could not find "store" in either the context or props of "Connect(Component)". Either wrap the root component in a `<Provider>`, or explicitly pass "store" as a prop to "Connect(Component)".

Is there a way to unwrap or stub the InnerContainer for unit testing without having to use shallow rendering?

Upvotes: 18

Views: 5328

Answers (4)

Rahul Gaba
Rahul Gaba

Reputation: 480

Mock the Provider component to return the child component.

Add this before describe().

jest.mock('Provider', () => ({children}) => children);

Upvotes: 0

type_master_flex
type_master_flex

Reputation: 1

Not sure if this is what your problem is, but I'm sure this will probably help a few people out there looking at this feed.

I had the same error and it was a simple fix:

I had forgotten to pass my component my store object in my entry file (using webpack).

I just added an attribute to the Root component "store={store}" see below:

    document.addEventListener("DOMContentLoaded", () => {
      const store = configureStore();
       ReactDOM.render(<Root store={store} />, 
     document.getElementById('content'));
    });

This was my root file code for reference as well:

    import React from 'react';
    import { Provider } from 'react-redux';
    import App from './app';

    const Root = ({ store }) => (
     <Provider store={ store }>
        <App />
     </Provider>
    );

export default Root;

Hope that helps someone!

Upvotes: 0

sospedra
sospedra

Reputation: 14734

Another approach is to export both the component to be connected and the container. The container as default, of course.

export const Comp = (props) => (<p>Whatever</p>)
export default connect(...)(Comp)

Hence, you can unit test Comp.

Upvotes: 0

Dan Abramov
Dan Abramov

Reputation: 268255

Wrap your component in <Provider> when testing. It’s up to you whether to supply a real store or a mock with { dispatch, getState, subscribe } to it. Wrapping the outermost component in <Provider store={store}> will also make the store available to the child components at any level of nesting—just like in the app itself.

const store = createStore(reducer) // can also be a mock
ReactTestUtils.renderIntoDocument(
  <Provider store={store}>
    <OuterContainer />
  </Provider>
)

Upvotes: 23

Related Questions