I'm learning how to test React/Redux components using enzyme. The component takes app-level state as props. When I run the test, I get the errors:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
TypeError: Cannot read property 'contextTypes' of undefined
with my console.log of wrapper
in the below test file logging as undefined
.
I know that there's something wrong with my setup here, and have spent a couple hours trying to figure this out. Can anybody see anything obvious in the way that I'm importing and trying to use the component? I can't figure out why it is undefined
. Thanks in advance for any help or insight!
BackendDisplay.js
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
var BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props.loginState;
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
const mapStateToProps = function(store) {
return store;
}
module.exports = connect(mapStateToProps)(BackendDisplay);
BackendDisplay.test.js
'use strict';
import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import { BackendDisplay } from '../components/BackendDisplay';
describe('<BackendDisplay />', () => {
it('Correctly displays username, node_version, app_path, and timestamp', () => {
const wrapper = shallow(<BackendDisplay />);
console.log(wrapper);
});
});
Edited after changes: BackendDisplay.js
import React from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
var BackendDisplay = React.createClass({
render() {
const { username, node_version, app_path, timestamp } = this.props.loginState;
const dateTime = moment(timestamp).format('MMMM Do YYYY, h:mm:ss a');
return (
<div>
<h1>Welcome, {username}!</h1>
<p><span className="bold">Node Version:</span> {node_version}</p>
<p><span className="bold">Application Path:</span> {app_path}</p>
<p><span className="bold">Date/Time:</span> {dateTime}</p>
</div>
);
}
});
const mapStateToProps = function(store) {
return store;
}
// module.exports = connect(mapStateToProps)(BackendDisplay);
export default connect(mapStateToProps)(BackendDisplay);
BackendDisplay.test.js
'use strict';
import React from 'react';
import {shallow} from 'enzyme';
import { connect } from 'react-redux';
import store from '../store';
import { Provider } from 'react-redux';
import ConnectedBackendDisplay, {BackendDisplay} from '../components/BackendDisplay';
describe('<BackendDisplay />', () => {
it('Correctly displays username, node_version, app_path, and timestamp', () => {
const wrapper = shallow(
<Provider store={store}>
<BackendDisplay />
</Provider>
);
console.log(wrapper.find(BackendDisplay));
expect(wrapper.find(BackendDisplay).length).to.equal(1);
});
});
Error message:
TypeError: Enzyme::Selector expects a string, object, or Component Constructor
Your BackendDisplay is a container component and it is connected to the Redux store through the use of the connect api.
You should export the undecorated component for testing purposes. Since it is undecorated this exported component will not be wrapped with react-redux's Connect component.
Then you can import it as follows to make the test work
As a bonus you can also export the decorated BackendDisplay component by changing the following line
to
This is how to import both the decorated and undecorated components
ConnectedBackendDisplay refers to the decorated component which is exported through the unnamed export (export default BackendDisplay).
We just give it this name so that its clear it is wrapped in a connect component.
I have updated the following component to use export default which gives an unnamed export.
BackendDisplay
Here is the test suite to demonstrate testing the above component both as a decorated and undecorated component with enzyme.
I am using the chai library to make test assertions easier. The jsdom library is also being used to create a DOM environment so we can test components using Enzyme's mount function which fully renders components.
test