have problem with testing redux connected component with enzyme
import React from 'react'
import { shallow, mount, render } from 'enzyme'
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
import Login from '../../src/routes/login/components/Login'
configure({ adapter: new Adapter() })
describe('<Login />', () => {
test('component has form-group nodes', () => {
const component = shallow(<Login />).dive()
expect(component.find('.form-group')).to.have.length(2)
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
But have error in console - Invariant Violation: Could not find "store" in either the context or props of "Connect(Login)".
how to deal with it??
I faced a similar problem and I managed to solve it by using redux-mock-store for my store mocking and I used mount instead of shallow to reach my connected component with redux like that:
import React, { Component } from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import App from '../../src/App';
it('renders without crashing', () => {
const mockStore = configureStore();
const initialState = {
someState: [],
someReducer: {},
};
const store = mockStore(initialState);
const wrapper = mount(
<Provider store={store}>
<App />
</Provider>
);
console.log(wrapper.debug())
expect(wrapper.find('.app-container')).to.have.lengthOf(1);
});
Have a read this best practice from [redux doc][1]
https://github.com/reduxjs/redux/blob/master/docs/recipes/WritingTests.md#connected-components
The issue you have encountered is because you are testing the connected component, what you should be doing is like what the official doc suggested:
export class Login extends Component { /* ... */ }
export default connect(mapStateToProps)(Login )
Instead of unit testing the connected component, you can simply unit test the Login component which you won't need to mock the store etc.
Hope it helps.
Related
I have looked at several answers but all recommend to wrap the main component in a Provider.
I have already done that but the error remains.
This is my App.js component
const App = ({ store }) =>
<Provider store={store}>
<div className="App">
<Users/>
</div>
</Provider>
And I am doing a very simple test. First time using enzyme,
import React from 'react'
import Adapter from 'enzyme-adapter-react-16'
import Users from './'
import { shallow, configure } from 'enzyme'
configure({adapter: new Adapter()});
describe('First React component test with Enzyme', () => {
it('renders without crashing', () => {
shallow(<Users />);
});
});
The error is:
Invariant Violation: Could not find "store" in the context of "Connect(Users)". Either wrap the root component in a Provider, or pass a custom React context provider to Provider and the corresponding React context consumer to Connect(Users) in connect options.
A possible solution is as follows:
import React from "react";
import { shallow } from "enzyme";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import Userfrom "../User";
const mockStore = configureMockStore();
const store = mockStore({});
describe('First React component test with Enzyme', () => {
it('renders without crashing', () => {
shallow(
<Provider store={store}>
<User/>
</Provider>
);
});
});
When i run my tests, i get the error:
Field must be inside a component decorated with reduxForm()
I am mocking a store, so i would think that would take care of injecting redux on the test but, i'm not really sure.
Inside appointments.js I have a component that has a redux form
import React from 'react';
... other imports
import configureMockStore from 'redux-mock-store';
import { mount } from 'enzyme';
import expect from 'expect';
import { Provider } from 'react-redux';
import { IntlProvider } from 'react-intl';
import LoginSection from '../User/LoginSection';
import AppointmentsContainer from './AppointmentsContainer';
import Appointments from './Appointments';
import AppointmentStatus from .../Layout/AppointmentStatus/AppointmentStatusContainer';
jest.mock('./Appointments');
jest.mock('../User/LoginSection');
jest.mock('../Layout/AppointmentStatus/AppointmentStatusContainer');
const store = configureMockStore()({
form: 'Appointments',
});
const setup = (newProps) => {
const props = {
handleSubmit: jest.fn(),
},
form: 'appointmentsContainer',
locale: 'en',
...newProps,
};
const root = mount(
<Provider store={store}>
<IntlProvider {...props}>
<AppointmentsContainer {...props} />
</IntlProvider>
</Provider>
,
);
const wrapper = root.find(Appointments);
return {
root,
wrapper,
props,
};
};
describe('AppointmentsContainer', () => {
beforeEach(() => {
store.clearActions();
});
Any idea how can i fix this?
I'm trying to setup testing on a new project created with react-create-app. Which now seems to be using React 16 and Jest 3 (which supposedly had some breaking changes, or maybe that was enzime). I'm getting an error similar to this post TypeError: dispatch is not a function when I try to test a method using JEST
TypeError: dispatch is not a function
at App.componentDidMount (src/components/App.js:21:68)
import React from 'react';
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import { App } from '../components/App';
import configureStore from '../state/store/configureStore';
window.store = configureStore({
slider: {
mainImageIndex: 0,
pageNum: 1,
perPage: 4,
},
});
const appTest = (
<Provider store={window.store}>
<App />
</Provider>
);
describe('App', () => {
it('should render without crashing', () => {
mount(appTest);
});
});
Originally I just tried to do this:
import React from 'react';
import { mount } from 'enzyme';
import { App } from '../components/App';
describe('App', () => {
it('should render without crashing', () => {
mount(<App />);
});
});
Which threw this error
Invariant Violation: Could not find "store" in either the context or props of "Connect(Form(SearchForm))". Either wrap the root component in a , or explicitly pass "store" as a prop
Code for App.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { searchPhotos } from '../state/actions/searchPhotos';
import { setMainImageIndex, setFirstPage } from '../state/actions/slider';
import Slider from './Slider';
import SearchForm from './SearchForm';
import Error from './Error';
import '../styles/App.css';
export class App extends Component {
componentDidMount() {
const { dispatch } = this.props;
dispatch(searchPhotos(window.store));
}
searchPhotosSubmit = () => {
const { dispatch } = this.props;
dispatch(setFirstPage());
dispatch(setMainImageIndex(0));
dispatch(searchPhotos(window.store));
}
render() {
const { fetchError } = this.props;
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Flickr Slider in React.js</h1>
<SearchForm onSubmit={this.searchPhotosSubmit} />
</header>
{!fetchError ? <Slider /> : <Error />}
</div>
);
}
}
export default connect(state => ({
fetchError: state.fetchError,
form: state.form,
slider: state.slider,
}))(App);
Please not that you export both presentational component (as named export) and container component (as default export) in App.js. Then in your tests you import and use the presentational component using:
import { App } from '../components/App';
but you should import connected container component instead using:
import App from '../components/App'; // IMPORTANT! - no braces around `App`
Since you're using component that is not connected to Redux store dispatch prop is not injected as prop. Just use correct import and it should work.
For more details about importing default and named exports please check this doc. About presentational and container components you can read here.
I am new to react and redux.
I am developing a project and for that I want to have redux, by using reduxsauce and redux-saga, but I am struggling to write unit tests for these.
Here is my folder structure:
My App-test.js:
import App from '../../../assets/src/App'
import React from 'react';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store'
import createStore from './Redux'
describe('App', () => {
const initialState = {output:100}
const mockStore = configureStore()
let store,container
const store = createStore()
beforeEach(()=>{
store = mockStore(initialState)
container = shallow(<App store={store} /> )
})
it('renders correctly', () => {
const rendered = renderer.create(
<App/>
);
expect(rendered.toJSON()).toMatchSnapshot();
});
});
Here is my App.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Index from './Screens/Index';
import { Provider } from 'react-redux'
import createStore from './Redux'
const store = createStore()
const rootElement = document.getElementById('subscription');
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<Index />
</Provider>
);
}
}
ReactDOM.render(<App />, rootElement);
I have tried with both the mockStore and store variable, but I am getting following error:
Any suggestions what could be wrong here?
Thanks
UPDATE 1
I muted the code now for shallow, and now my App-test.js file looks like this:
import App from '../../../assets/src/App'
import React from 'react';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store'
import createStore from './Redux'
describe('App', () => {
const initialState = {output:100}
const mockStore = configureStore()
let store,container
const store = createStore()
// beforeEach(()=>{
//// store = mockStore(initialState)
// container = shallow(<App store={store} /> )
// })
it('renders correctly', () => {
const rendered = renderer.create(
<App/>
);
expect(rendered.toJSON()).toMatchSnapshot();
});
});
But I get different error now:
UPDATE 2
After trying the solution as suggested by Rami Enbashi in the answer, the previous error (before UPDATE 1) again started appearing.
This seems to be a transpilation issue. You need to register Babel so that it will transpile ES6 to ES5 before you run unit tests. One way to do it is this.
In package.json add this jest config:
"jest": {
"setupTestFrameworkScriptFile": "./scripts/testsetup.js"
}
and in testsetup.js add this
require('babel-register')();
require("babel-polyfill");
require("babel-jest");
.....
Make sure you read Jest documentation for more config or needed plugins. And make sure you install them first.
I'm trying to test a React component with enzyme and mocha as follows
import { mount, shallow } from 'enzyme';
import React from 'react';
import chai, { expect } from 'chai'
import chaiEnzyme from 'chai-enzyme'
import sinon from 'sinon'
import MyComponent from 'myComponent'
chai.use(chaiEnzyme())
describe('MyComponent', () => {
const store = {
id: 1
}
it ('renders', () => {
const wrapper = mount(<MyComponent />, {context: {store: store}})
})
})
haven't actually written the test as it fails at the declaration of wrapper
Error message: TypeError: _this.store.getState is not a function
No idea what the problem is and cant find anything addressing this!
Any help would be great!
This error means that store can't get the state correctly.
I would recommend mocking the store using redux-mock-store
and import configureStore
import configureStore from 'redux-mock-store';
then mock the state by doing this
const initialState = { id: 1 };
const mockStore = configureStore();
and you can continue by wrapping your component with provider
import { Provider } from 'react-redux'; // add this to the top of your file
const wrapper = mount(
<Provider store={mockStore(initialState)}>
<MyComponent />
</Provider>,
);
Also, shouldn't chai.user() be chai.use() in your code example?