18

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?

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Jon Yardley
  • 183
  • 1
  • 5

4 Answers4

23

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>
)
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • Great! Thanks for the advice. Giving this a go now :) – Jon Yardley Mar 23 '16 at 15:07
  • Works like a charm. Thanks again @DanAbramov ! – Jon Yardley Mar 23 '16 at 16:57
  • 4
    @dan-abramov: this works. However, it's not really a unit test anymore. Enzyme has `shallow`, but it still goes deep with a connected child component. Do you have any idea if it's possible to just test if `` is there without rendering it? – publicJorn Feb 09 '17 at 14:27
  • I echo @publicJorn concern. I like this solution myself, but it makes the tests way more complex than they should be. – csvan May 31 '17 at 11:29
0

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.

sospedra
  • 14,238
  • 3
  • 21
  • 32
  • But this defeats the purpose of testing the component with complete Redux linkage. Won't it? – shobhit1 Mar 18 '17 at 05:35
  • 1
    @shobhit1 but then you're testing your component and `connect` which is already tested by `react-redux`. Is not bad, neither good. You're just overtesting then. – sospedra Mar 21 '17 at 12:33
  • 1
    This will not work if, as in the question, `Comp` itself imports and uses another container. The subcontainer will then expect `store` to be present, and the test will fail. – csvan May 31 '17 at 11:32
0

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!

0

Mock the Provider component to return the child component.

Add this before describe().

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

Rahul Gaba
  • 460
  • 4
  • 6