I have component in React which I'm trying to test with Jest, unfortunately test do not pass.
The component code:
import React, {Component} from 'react';
import ProductItem from '../ProductItem/ProductItem';
import AppBar from "@material-ui/core/es/AppBar/AppBar";
import Tabs from "@material-ui/core/es/Tabs/Tabs";
import Tab from "@material-ui/core/es/Tab/Tab";
import {connect} from 'react-redux';
class ProductsTabsWidget extends Component {
state = {
value: 0
}
renderTabs = () => {
return this.props.tabs.map((item, index) => {
return item.products.length > 0 ? (<Tab key={index} label={item.title}/>) : false;
})
}
handleChange = (event, value) => {
this.setState({value});
};
renderConentActiveTab = () => {
if (this.props.tabs[this.state.value]) {
return this.props.tabs[this.state.value].products.map((productIndex) => {
return (<ProductItem key={productIndex} {...this.props.products[productIndex]} />);
});
}
}
render() {
let tabs = null;
let content = null;
if (this.props.tabs) {
tabs = this.renderTabs();
content = this.renderConentActiveTab();
}
return (
<div>
<AppBar position="static" color="default">
<Tabs
value={this.state.value}
onChange={this.handleChange}
indicatorColor="primary"
textColor="primary"
centered
scrollButtons="auto"
>
{tabs}
</Tabs>
</AppBar>
<div className="productWidget">
<div className="wrapper">
{content}
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
products: state.product.products,
}
}
export default connect(mapStateToProps)(ProductsTabsWidget);
I have tried to write proper test for this component, the code is below:
import React from 'react';
import {configure, shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ProductsTabsWidget from "./ProductsTabsWidget";
configure({adapter: new Adapter()});
describe('ProductsTabsWidget - component', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<ProductsTabsWidget/>);
});
it('renders with minimum props without exploding', () => {
wrapper.setProps({
tabs: [],
products:[]
});
expect(wrapper).toHaveLength(1);
});
})
But when I'm running test I am getting error:
Test suite failed to run
F:\PRACA\reactiveShop\node_modules\@material-ui\core\es\AppBar\AppBar.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import _extends from "@babel/runtime/helpers/builtin/extends";
^^^^^^
SyntaxError: Unexpected token import
at new Script (vm.js:51:7)
at Object.<anonymous> (src/components/product/ProductsTabsWidget/ProductsTabsWidget.js:3:15)
I have tried testing with shallow
, mount
, render
but it did not help. What am I missing?
My application is created on create-react-app
.
Following is a humble attempt to provide a more complete answer from create-react-app
and @material-ui
perspective.
1.
Create setupTests.js
directly in src
folder and paste the following code.
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });
2.
The following is react stateless component which uses material-ui
components.
import React from "react";
import TextField from "@material-ui/core/TextField";
const SearchField = props => (
<TextField InputProps={{ disableUnderline: true }} fullWidth
placeholder={props.placeholder}
onChange={props.onChange}
/>
);
export default SearchField;
Note that in the above component, the component expects parent component to pass the props for placeholder
and onChange()
event handler
3.
Coming to the test case for for the above component we can write either in a way material-ui
suggests or in a pure enzyme
style. Both will work.
Pure Enzyme
Style
import React from "react";
import { mount } from "enzyme";
import TextField from "@material-ui/core/TextField";
import SearchField from "../SearchField";
describe("SearchField Enzyme mount() ", () => {
const fieldProps = {
placeholder: "A placeholder",
onChange: jest.fn()
};
const Composition = props => {
return <SearchField {...fieldProps} />;
};
it("renders a <TextField/> component with expected props", () => {
const wrapper = mount(<Composition />);
expect(wrapper.childAt(0).props().placeholder).toEqual("A placeholder");
expect(wrapper.childAt(0).props().onChange).toBeDefined();
});
it("should trigger onChange on <SearchField/> on key press", () => {
const wrapper = mount(<Composition />);
wrapper.find("input").simulate("change");
expect(fieldProps.onChange).toHaveBeenCalled();
});
it("should render <TextField />", () => {
const wrapper = mount(<Composition />);
expect(wrapper.find(TextField)).toHaveLength(1);
expect(wrapper.find(TextField).props().InputProps.disableUnderline).toBe(
true
);
});
});
Material UI
style
import React from "react";
import { createMount } from "@material-ui/core/test-utils";
import TextField from "@material-ui/core/TextField";
import SearchField from "../SearchField";
describe("SearchField", () => {
let mount;
const fieldProps = {
placeholder: "A placeholder",
onChange: jest.fn()
};
beforeEach(() => {
mount = createMount();
});
afterEach(() => {
mount.cleanUp();
});
it("renders a <TextField/> component with expected props", () => {
const wrapper = mount(<SearchField {...fieldProps} />);
expect(wrapper.props().placeholder).toEqual("A placeholder");
expect(wrapper.props().onChange).toBeDefined();
});
it("should trigger onChange on <SearchField/> on key press", () => {
const wrapper = mount(<SearchField {...fieldProps} />);
wrapper.find("input").simulate("change");
expect(fieldProps.onChange).toHaveBeenCalled();
});
});
5.
The error you are getting is due to the fact that babel
is not getting a chance to process your file. The create-react-app
expects you to run tests like yarn run test
and not like jest your/test/file.js
. If you use latter babel
won't be employed
.
If you want to use jest
to run the file you will have to write a jest.config.js
file or configure jest
in package.json
file to use babel-jest
+ other babel dependencies
to transpile your code before jest tries to execute tests.
I was in the same boat yesterday as I tried to use @material-ui
for the first time and came here to get a more complete answer.
It's something different when you're using @material-ui
.
You've to use @material-ui
's Built-in API(s). Such as createMount
, createShallow
, createRender
in order to use enzyme's shallow
, mount
& render
.
These APIs are built on top of enzyme
, so you can't use enzyme
directly for testing @material-ui
.
Shallow
Rendering with @material-uiimport { createShallow } from '@material-ui/core/test-utils';
describe('<MyComponent />', () => {
let shallow;
before(() => {
shallow = createShallow();
});
it('should work', () => {
const wrapper = shallow(<MyComponent />);
});
});
Reference: Official Docs of @material-ui
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With