user11092881
user11092881

Reputation:

Invariant Violation: Could not find "store" in the context of "Connect(AddTodo)".when executing npm test

https://github.com/RitikPatni/react-todo

When running "npm test" I get the following:

Invariant Violation: Could not find "store" in the context of "Connect(AddTodo)". Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(AddTodo) in connect options.

I am pretty sure it comes from the line inside components/addTodo.js:

export default connect()(AddTodo);

But I am not sure what I should modify in order for the test to run successfully without breaking the application.

This is the test that fails and it's inside App.test.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
  ReactDOM.unmountComponentAtNode(div);
});

After reading Drew Reese's excellent answer I tried this:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import todo from './reducers/todo'

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(
    <Provider store={createStore(todo, [{
      id: 1,
      dueDate: new Date('July 22, 2018 07:22:13').toDateString(),
      completed: false,
      text: 'Run the tests',
      deleted: false,
  }])}>
      <App />
    </Provider>,
    div
  );
  ReactDOM.unmountComponentAtNode(div);
});

However, I am getting:

 FAIL  src/App.test.js
  ● Console

    console.log src/reducers/todo.js:2
      { type: '@@redux/INIT1.z.e.5.x' }
    console.error node_modules/react-dom/cjs/react-dom.development.js:530
      Warning: Invalid DOM property `class`. Did you mean `className`?
          in span (at addTodo.js:38)
          in form (at addTodo.js:10)
          in div (at addTodo.js:9)
          in AddTodo (created by Context.Consumer)
          in Connect(AddTodo) (at App.js:7)
          in div (at App.js:5)
          in App (at App.test.js:18)
          in Provider (at App.test.js:11)
    console.error node_modules/prop-types/checkPropTypes.js:20
      Warning: Failed prop type: The prop `todos` is marked as required in `TodoList`, but its value is `undefined`.
          in TodoList (created by Context.Consumer)
          in Connect(TodoList) (at App.js:8)
          in div (at App.js:5)
          in App (at App.test.js:18)
          in Provider (at App.test.js:11)
    console.error node_modules/prop-types/checkPropTypes.js:20
      Warning: Failed prop type: The prop `toggleTodo` is marked as required in `TodoList`, but its value is `undefined`.
          in TodoList (created by Context.Consumer)
          in Connect(TodoList) (at App.js:8)
          in div (at App.js:5)
          in App (at App.test.js:18)
          in Provider (at App.test.js:11)
    console.error node_modules/prop-types/checkPropTypes.js:20
      Warning: Failed prop type: The prop `removeTodo` is marked as required in `TodoList`, but its value is `undefined`.
          in TodoList (created by Context.Consumer)
          in Connect(TodoList) (at App.js:8)
          in div (at App.js:5)
          in App (at App.test.js:18)
          in Provider (at App.test.js:11)
    console.error node_modules/react-dom/cjs/react-dom.development.js:21843
      The above error occurred in the <Context.Consumer> component:
          in Connect(TodoList) (at App.js:8)
          in div (at App.js:5)
          in App (at App.test.js:18)
          in Provider (at App.test.js:11)

      Consider adding an error boundary to your tree to customize error handling behavior.
      Visit https://reactjs.org/docs/error-boundaries.html to learn more about error boundaries.

  ● renders without crashing

    Unknown filter: undefined

       8 |       return todos;
       9 |     default:
    > 10 |       throw new Error('Unknown filter: ' + filter);
         |             ^
      11 |   }
      12 | };
      13 | 

      at getVisibleTodos (src/components/visibleTodoList.js:10:13)
      at Function.mapStateToProps [as mapToProps] (src/components/visibleTodoList.js:16:12)
      at mapToPropsProxy (node_modules/react-redux/lib/connect/wrapMapToProps.js:53:92)
      at Function.detectFactoryAndVerify (node_modules/react-redux/lib/connect/wrapMapToProps.js:62:19)
      at mapToPropsProxy (node_modules/react-redux/lib/connect/wrapMapToProps.js:53:46)
      at handleFirstCall (node_modules/react-redux/lib/connect/selectorFactory.js:34:18)
      at pureFinalPropsSelector (node_modules/react-redux/lib/connect/selectorFactory.js:75:81)
      at Connect.selectDerivedProps (node_modules/react-redux/lib/components/connectAdvanced.js:126:25)
      at Connect.renderWrappedComponent (node_modules/react-redux/lib/components/connectAdvanced.js:183:33)
      at Connect.indirectRenderWrappedComponent (node_modules/react-redux/lib/components/connectAdvanced.js:168:21)
      at updateContextConsumer (node_modules/react-dom/cjs/react-dom.development.js:19844:19)
      at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:20227:14)
      at beginWork$$1 (node_modules/react-dom/cjs/react-dom.development.js:25756:14)
      at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:24698:12)
      at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:24671:22)
      at performSyncWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:24270:11)
      at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:23698:7)
      at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:27103:3)
      at node_modules/react-dom/cjs/react-dom.development.js:27528:7
      at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:24433:12)
      at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:27527:5)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:27608:10)
      at Object.<anonymous>.it (src/App.test.js:10:12)

Tried:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import todo from './reducers/todo'
import rootReducer from './reducers/';

const store = createStore(rootReducer);


it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(
    <Provider store={store}>
      <App />
    </Provider>,
    div
  );
  ReactDOM.unmountComponentAtNode(div);
});

And now the test passes. Not sure if it's ok to pass the rootReducer store though.

Upvotes: 0

Views: 2787

Answers (1)

Drew Reese
Drew Reese

Reputation: 202618

The usual pattern is to also export the "unconnected" component for testing and manually pass the props (mapped from state) the connect HOC (Higer Order Component) provides, this way you won't have to mock up a redux store provider or create a wrapper for testing.

export const MyComponent = ({ myProp }) => {
  return (<div>{myProp}</div>);
};

const mapStateToProps = state => ({ myProp: state.someStateValue });

export default connect(mapStateToProps)(MyComponent);

testing MyComponent

// all the other testing imports
import { MyComponent } from './MyComponent'; // notice using named unconnected component, not the default export

it('renders without crashing', () => {
  // Something like this
  // render(<MyComponent myProp={ /* some value for testing */} />);
});

In some cases if you are testing a component that renders a connected component then you'll need to provide a wrapper that provides the context to the component needing it.

In your app test you need to render with a wrapper that provides a store:

import { createStore } from 'redux;
import { Provider } from 'react-redux';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(
    <Provider store={createStore(reducer, initialState)}>
      <App />
    </Provider>,
    div
  );
  ReactDOM.unmountComponentAtNode(div);
});

Upvotes: 1

Related Questions