Not sure why I'm getting this error, it happened when I added connect
from redux
to my Login ponent, so I could connect my store
.
FAIL src/ponents/auth/Login.test.js
● Test suite failed to run
Invariant Violation: Could not find "store" in either the context or props of "Connect(LoginContainer)". Either wrap the root ponent in a
<Provider>
, or explicitly pass "store" as a prop to "Connect(LoginContainer)".
Index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from "react-redux"
import { createCommonStore } from "./store";
import App from './App'
import css from './manage2.scss'
const store = createCommonStore();
const element = document.getElementById('manage2');
console.log("Index.js Default store", store.getState());
ReactDOM.render(
<Provider store={store}> // <-- store added here
<App />
</Provider>, element);
store.js
import React from "react"
import { applyMiddleware, bineReducers, pose, createStore} from "redux"
import thunk from "redux-thunk"
import { userReducer } from "./reducers/UserReducer"
import { authReducer } from "./reducers/AuthReducer"
export const createCommonStore = (trackStore=false) => {
const reducers = bineReducers({
user: userReducer,
user: authReducer
});
//noinspection JSUnresolvedVariable
const store = createStore(reducers,
pose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
if (trackStore) {
store.subscribe((() => {
console.log(" store changed", store.getState());
}));
}
return store;
};
App.js
import React from 'react'
import { BrowserRouter as Router } from 'react-router-dom'
import Routes from './ponents/Routes'
const supportsHistory = "pushState" in window.history
export default class App extends React.Component {
render() {
return (
<Router forceRefresh={!supportsHistory}>
<Routes />
</Router>
);
}
}
Routes.js
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import LoginContainer from './auth/Login'
import Dashboard from './Dashboard'
import NoMatch from './NoMatch'
const Routes = () => {
return (
<Switch>
<Route exact={ true } path="/" ponent={ LoginContainer }/>
<Route path="/dashboard" ponent={ Dashboard }/>
<Route ponent={ NoMatch } />
</Switch>
);
}
export default Routes
Finally Login.js (code removed for brevity
import React from 'react'
import { connect } from "react-redux"
import { bindActionCreators } from 'redux';
import { setCurrentUser } from '../../actions/authActions'
import * as api from '../../services/api'
const mapDispatchToProps = (dispatch) => {
console.log('mapDispatchToProps', dispatch);
return {
setUser: (user) => {
bindActionCreators(setCurrentUser(user), dispatch)
}
}
}
class LoginContainer extends React.Component {
constructor(props) {
super(props)
this.state = {};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
}
handleSubmit(e) {
}
render() {
return (
<div className="app-bg">
...
</div>
)
}
}
export default connect(null, mapDispatchToProps)(LoginContainer);
Login.test
import React from 'react'
import ReactTestUtils from 'react-dom/test-utils'
import { mount, shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { missingLogin } from '../../consts/errors'
import Login from './Login'
import Notification from '../mon/Notification'
const loginComponent = shallow(<Login />);
const fakeEvent = { preventDefault: () => '' };
describe('<Login /> ponent', () => {
it('should render', () => {
const tree = toJson(loginComponent);
expect(tree).toMatchSnapshot();
});
it('should render the Notification ponent if state.error is true', () => {
loginComponent.setState({ error: true });
expect(loginComponent.find(Notification).length).toBe(1);
});
});
describe('User Login', () => {
it('should fail if no credentials are provided', () => {
expect(loginComponent.find('.form-login').length).toBe(1);
loginComponent.find('.form-login').simulate('submit', fakeEvent);
expect(loginComponent.find(Notification).length).toBe(1);
const notificationComponent = shallow(<Notification message={ missingLogin }/>);
expect(notificationComponent.text()).toEqual('Please fill out both username and password.');
});
it('input fields should be filled correctly', () => {
const credentials = { username: 'leongaban', password: 'testpass' };
expect(loginComponent.find('#input-auth-username').length).toBe(1);
const usernameInput = loginComponent.find('#input-auth-username');
usernameInput.value = credentials.username;
expect(usernameInput.value).toBe('leongaban');
const passwordInput = loginComponent.find('#input-auth-password');
passwordInput.value = credentials.password;
expect(passwordInput.value).toBe('testpass');
});
});
What do you see wrong here?
Not sure why I'm getting this error, it happened when I added connect
from redux
to my Login ponent, so I could connect my store
.
FAIL src/ponents/auth/Login.test.js
● Test suite failed to run
Invariant Violation: Could not find "store" in either the context or props of "Connect(LoginContainer)". Either wrap the root ponent in a
<Provider>
, or explicitly pass "store" as a prop to "Connect(LoginContainer)".
Index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from "react-redux"
import { createCommonStore } from "./store";
import App from './App'
import css from './manage2.scss'
const store = createCommonStore();
const element = document.getElementById('manage2');
console.log("Index.js Default store", store.getState());
ReactDOM.render(
<Provider store={store}> // <-- store added here
<App />
</Provider>, element);
store.js
import React from "react"
import { applyMiddleware, bineReducers, pose, createStore} from "redux"
import thunk from "redux-thunk"
import { userReducer } from "./reducers/UserReducer"
import { authReducer } from "./reducers/AuthReducer"
export const createCommonStore = (trackStore=false) => {
const reducers = bineReducers({
user: userReducer,
user: authReducer
});
//noinspection JSUnresolvedVariable
const store = createStore(reducers,
pose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
if (trackStore) {
store.subscribe((() => {
console.log(" store changed", store.getState());
}));
}
return store;
};
App.js
import React from 'react'
import { BrowserRouter as Router } from 'react-router-dom'
import Routes from './ponents/Routes'
const supportsHistory = "pushState" in window.history
export default class App extends React.Component {
render() {
return (
<Router forceRefresh={!supportsHistory}>
<Routes />
</Router>
);
}
}
Routes.js
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import LoginContainer from './auth/Login'
import Dashboard from './Dashboard'
import NoMatch from './NoMatch'
const Routes = () => {
return (
<Switch>
<Route exact={ true } path="/" ponent={ LoginContainer }/>
<Route path="/dashboard" ponent={ Dashboard }/>
<Route ponent={ NoMatch } />
</Switch>
);
}
export default Routes
Finally Login.js (code removed for brevity
import React from 'react'
import { connect } from "react-redux"
import { bindActionCreators } from 'redux';
import { setCurrentUser } from '../../actions/authActions'
import * as api from '../../services/api'
const mapDispatchToProps = (dispatch) => {
console.log('mapDispatchToProps', dispatch);
return {
setUser: (user) => {
bindActionCreators(setCurrentUser(user), dispatch)
}
}
}
class LoginContainer extends React.Component {
constructor(props) {
super(props)
this.state = {};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
}
handleSubmit(e) {
}
render() {
return (
<div className="app-bg">
...
</div>
)
}
}
export default connect(null, mapDispatchToProps)(LoginContainer);
Login.test
import React from 'react'
import ReactTestUtils from 'react-dom/test-utils'
import { mount, shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { missingLogin } from '../../consts/errors'
import Login from './Login'
import Notification from '../mon/Notification'
const loginComponent = shallow(<Login />);
const fakeEvent = { preventDefault: () => '' };
describe('<Login /> ponent', () => {
it('should render', () => {
const tree = toJson(loginComponent);
expect(tree).toMatchSnapshot();
});
it('should render the Notification ponent if state.error is true', () => {
loginComponent.setState({ error: true });
expect(loginComponent.find(Notification).length).toBe(1);
});
});
describe('User Login', () => {
it('should fail if no credentials are provided', () => {
expect(loginComponent.find('.form-login').length).toBe(1);
loginComponent.find('.form-login').simulate('submit', fakeEvent);
expect(loginComponent.find(Notification).length).toBe(1);
const notificationComponent = shallow(<Notification message={ missingLogin }/>);
expect(notificationComponent.text()).toEqual('Please fill out both username and password.');
});
it('input fields should be filled correctly', () => {
const credentials = { username: 'leongaban', password: 'testpass' };
expect(loginComponent.find('#input-auth-username').length).toBe(1);
const usernameInput = loginComponent.find('#input-auth-username');
usernameInput.value = credentials.username;
expect(usernameInput.value).toBe('leongaban');
const passwordInput = loginComponent.find('#input-auth-password');
passwordInput.value = credentials.password;
expect(passwordInput.value).toBe('testpass');
});
});
What do you see wrong here?
Share Improve this question edited Jun 12, 2017 at 14:11 Leon Gaban asked Jun 9, 2017 at 13:05 Leon GabanLeon Gaban 39k122 gold badges348 silver badges550 bronze badges 7- where is createCommonStore code, – Shubham Khatri Commented Jun 9, 2017 at 13:06
- @ShubhamKhatri just added it sorry! store.js – Leon Gaban Commented Jun 9, 2017 at 13:11
- in your index.js do a console.log() to see if you get the store defiend – Shubham Khatri Commented Jun 9, 2017 at 13:17
- 1 can you provide login.test.js file? – lavish Commented Jun 9, 2017 at 13:28
- 1 How do you connect the store in the test? – Dave Newton Commented Jun 9, 2017 at 14:43
3 Answers
Reset to default 9 +100Redux remends exporting the unconnected ponent for unit tests. See their docs.
In login.js:
// Named export for tests
export class LoginContainer extends React.Component {
}
// Default export
export default connect(null, mapDispatchToProps)(LoginContainer);
And in your test:
// Import the named export, which has not gone through the connect function
import { LoginContainer as Login } from './Login';
You can then specify any props that would have e from the store directly on the ponent.
You need to pass store as either a prop or context in your test. mount method accepts context as another parameter.
and how do you get store here? You create store the same way you created in app.js
You could use React's contextType or pass propType. You would need to declare it either as a prop or contextType.
Provider.contextTypes = {
Store: React.PropTypes.object.isRequired
};
Provider.propTypes= {
Store: React.PropTypes.object.isRequired
};