JestJS -> Invariant Violation: Could not find “sto

2019-06-20 01:31发布

问题:

The full error message:

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

Not sure why I'm getting this error in my Jest tests as my app is working and I can change my state with dispatch actions.

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
import App from './App'

const element = document.getElementById('coinhover');

const store = createStore(reducer, compose(
    applyMiddleware(thunk),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));

ReactDOM.render(
    <Provider store={ store }>
        <App />
    </Provider>, element);

Portfolio component

import React from 'react'
import { connect } from 'react-redux'
import SocialMediaFooter from '../common/SocialMediaFooter'
import AssetsTable from '../assetsTable/AssetsTable'
import local_coins from '../../coins.json'
import * as api from '../../services/api'

const mapStateToProps = ({ portfolio }) => ({
    portfolio
});

let localCoins = local_coins;

class Portfolio extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            loading: true,
            assets: props.portfolio,
            total: 0
        };
    }

    componentDidMount() {
        this.setState({ loading: false });
    }

    render() {
        const assets = this.state.assets;
        const total  = this.state.total;

        return (
            <div className="app-bg">
                <section className="portfolio">
                    <header>
                        <h1><span className="plus">+</span>COINHOVER</h1>
                        <h2>Watch your cryptocurrency asset balances in once place.</h2>
                        <em className="num">${ total }</em>
                    </header>
                    { this.state.loading ? (
                        <div className="loading">
                            <div className="loader"></div>
                            <span>Loading coin data...</span>
                        </div>
                    ) : (
                        <AssetsTable assets={ assets }/>
                    )}
                    <SocialMediaFooter />
                </section>
            </div>
        )
    }
}

export default connect(mapStateToProps, null)(Portfolio)

回答1:

Per the error message, you need to make sure that tests for a connected component can actually access a store instance. So, in your test code, you should also use <Provider store={store}><ConnectedPortfolio /></Provider>, or <ConnectedPortfolio store={store} />. Or, you can export your plain Portfolio component separately, and test that, not the connected version.

See the Redux docs on testing for more info, as well as the articles on Redux testing approaches in my React/Redux links list.



回答2:

I ran into same issue, here is how I fixed it: As the official docs of redux suggest, better to export the unconnected component as well.

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:

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)

Since the default export is still the decorated component, the import statement pictured above will work as before so you won't have to change your application code. However, you can now import the undecorated App components in your test file like this:

// Note the curly braces: grab the named export instead of default export
import { App } from './App'

And if you need both:

import ConnectedApp, { App } from './App'

In the app itself, you would still import it normally:

import App from './App'

You would only use the named export for tests.