I am having some trouble with my test cases written in Jest / Enzyme. I have a React / Redux component and am trying to write a basic test but get the following error:
Invariant Violation: ReactShallowRenderer render(): Shallow rendering works only with custom components, but the provided element type was 'undefined'.
This is my code:
dashboardComponent.js
import '../stylesheets/dashboardComponent.css';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as dashboardActions from '../actions/dashboardActions';
class DashboardComponent extends Component {
constructor(props) {
super();
}
componentDidMount() {
this.props.actions.getDashboardContent();
}
render() {
return (
< SOME JSX HERE >
);
}
}
function mapStateToProps(state) {
return {
dashboardContent: state.dashboard.get('dashboardContent')
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(dashboardActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(DashboardComponent);
dashboardComponent.test.js
import React from 'react';
import { shallow } from 'enzyme';
import { DashboardComponent as Dashboard } from '../../components/dashboardComponent';
const wrapper = shallow(<Dashboard />);
describe('Dashboard', () => {
it('renders the Dashboard component', () => {
expect(wrapper).toMatchSnapshot();
});
});
I am not sure why <Dashboard /> would be undefined here.
You're currently exporting your wrapped component as the default export, but to use the unwrapped component in your tests you also need to export your it as a named export, i.e.
export class DashboardComponent extends Component { ... }
export default connect(...)(DashboardComponent)
Error: ReactShallowRenderer render(): Shallow rendering works only with custom components, but the provided element type was `object`.
- solved similar error by changing export line, from
export const TestComponent = () => { ...
to
export default TestComponent = () => { ...
Related
I have to do it a few simple React Enzyme tests. I want to check if component is rendered.
import React from 'react';
import { shallow } from 'enzyme';
import ConnSearch from './ConnSearch';
it('renders without errors', () => {
const component = shallow(<ConnSearch />);
console.log(component.debug());
});
I have results: Could not find "store" in the context of "Connect(ConnSearch)". Either wrap the root component in a , or pass a custom React context provider to a
nd the corresponding React context consumer to Connect(ConnSearch) in connect options.
My ConnSearch Component:
import React, { Component } from 'react';
import {fetchRoadDetails, fetchUserPoints} from "../../actions";
import {connect} from "react-redux";
import RoadTable from "../../components/RoadTable/RoadTable";
import RoadForm from "../../components/RoadTable/RoadForm";
import style from './ConnSearch.module.scss'
import {getPoints} from "../../reducers";
class ConnSearch extends Component {
constructor(props){
super(props);
this.state = {
};
}
componentDidMount() {
this.props.fetchUserPoints(this.props.userLogin);
}
render() {
return (
<div className={style.wrapper}>
<RoadForm />
<div className={style.tableWrapper} >
<RoadTable/>
</div>
</div>
);
}
}
const mapDispatchToProps=dispatch=>({
fetchRoadDetails:()=>dispatch(fetchRoadDetails()),
fetchUserPoints:(user)=>dispatch(fetchUserPoints(user)),
});
const mapStateToProps = (state) => {
return {
roads: state.road,
points:getPoints(state),
userLogin: state.userLogin,
};
};
export default connect(mapStateToProps,mapDispatchToProps)(ConnSearch);
How can I do this test ? I've never done that before.
Unfortunately, when I wrap it in a provider:
it('renders without errors', () => {
const component = shallow( <Provider store={store}><ConnSearch/></Provider>);
console.log(component.debug());
});
I got this:
console.log src/views/ConnectionSearch/ConnSearch.test.js:11
<ContextProvider value={{...}}>
<Connect(ConnSearch) />
</ContextProvider>
I want ConnSearch render structure.
I have developed an component in React Typescript which is working perfectly fine. Also, I have written an Unit Test for same, but we are getting below error for the Unit Test page
TS2305: Module '"/app/containers/OrderFailure"' has no exported member
'OrderFailure'.
OrderFailure Compontent:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'connected-react-router';
class OrderFailure extends Component<Props, State> {
}
const mapStateToProps = (state: any) => ({
orderDetails: state.orderReducer,
});
const mapDispatchToProps = {
push,
};
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
export default withConnect(OrderFailure);
Unit Test For Compontent:
import React from 'react';
import { IntlProvider } from 'react-intl';
import { render, fireEvent } from '#testing-library/react';
import { expect } from 'chai';
import { spy, assert } from 'sinon';
import { OrderFailure } from '../index';
describe('<OrderSuccess />', () => {
});
it('should call push with parameter on submit click', () => {
});
What I am missing, that while creating build I am getting error of no export
Created a simple app using create-react-app then updated my App.js and added redux/store.
class App extends Component {
render() {
return (
<header className="header">
<h1>todos</h1>
</header>
);
}
}
function mapStateToProps(state) {
return {
data: state.data
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
then trying to test my App on App.test.js using Enzyme and Jest.
import React from 'react'
import Enzyme, { mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16';
import App from './App'
Enzyme.configure({ adapter: new Adapter() });
function setup() {
const props = {
addTodo: jest.fn()
}
const enzymeWrapper = mount(<App {...props} />)
return {
props,
enzymeWrapper
}
}
describe('components', () => {
describe('App', () => {
it('should render self and subcomponents', () => {
const { enzymeWrapper } = setup()
expect(enzymeWrapper.find('header')).toBe(true)
})
})
})
but throwing error: Invariant Violation: Could not find "store" in either the context or props of "Connect(App)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(App)".
Any Ideas?
This is happening because you're trying to test the component without a <Provider> (which would normally make the store available to its sub-components).
What I normally do in this situation is test my component without the Redux connect binding. To do this, you can export the App component itself:
export class App extends Component // etc...
and then import that in the test file using the deconstructed assignment syntax:
import { App } from './App'
You can assume (hopefully... ;) ) that Redux and the React bindings have been properly tested by their creators, and spend your time on testing your own code instead.
There's a little more information about this in the Redux docs.
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.
Enzyme shallow rendering behaves in an unexpected way if I am rendering a redux component with a mocked store.
I have a simple test that looks like this :
import React from 'react';
import { shallow } from 'enzyme';
import { createMockStore } from 'redux-test-utils';
import Test from './Test'
it('should render ', () => {
const testState = {
app: {
bar: ['a', 'b', 'c']
}
};
const store = createMockStore(testState)
const context = {
store,
};
const shallowComponent = shallow(<Test items={[]}/>, {context});
console.log(shallowComponent.debug());
}
The Test component looks like :
class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div className="here"/>
)
}
}
export default Test;
Which as expected prints out this :
<div className="here" />
However if my component is a redux component :
class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div className="here"/>
)
}
}
const mapStateToProps = state => {
return {
barData: state.app.bar
}
}
export default connect(
mapStateToProps
)(Test)
Then what I get in the console is this :
<BarSeriesListTest items={{...}} barData={{...}} dispatch={[Function]} />
Why is there this difference? How do I test that my component has <div className="here"/> embedded in it in my redux version of the component?
You are referencing the HOC that connect is returning and not the component that you want to test.
You should use enzyme's dive function which will render the child component and return it as a wrapper.
const shallowComponent = shallow(<Test items={[]}/>, {context}).dive();
You can use it multiple times if you have multiple components that you need to dive through to get to. It's better than using mount as well because we are still testing in isolation.
You should export the unconnected component and test it separately (notice the first export):
export class Test extends React.Component {
}
...
export default connect(
mapStateToProps
)(Test)
While in your test you should test the rendering of the unconnected component like so (notice the curly braces around { Test }):
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import { Test } from './Test';
describe('...', () => {
it('...', () => {
const wrapper = shallow(<Test />)
expect(toJson(wrapper)).toMatchSnapshot();
})
})
Hope this helps.
Mode specifically for your described case the component should be:
import React from 'react';
import { connect } from 'react-redux';
export class Test extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div className="here"/>
)
}
}
const mapStateToProps = state => {
return {
barData: state.app.bar
}
}
export default connect(
mapStateToProps
)(Test)
The test spec should be:
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import { Test } from 'Test';
describe('Test component', () => {
it('renders', () => {
const wrapper = shallow(<Test />);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
Which generates the following snapshot:
exports[`Test component renders 1`] = `
<div
className="here"
/>
`;
You are exporting the connected component by default. What you can do is import the component that is not connected to redux.
import { Test } from './Test';
Then your test should work.