我尝试使用Material UI在React上运行一些简单的单元测试,但我收到的错误是我不知道原因,我已经使用MaterialUI运行了测试在没有问题的其他项目上。
这是我尝试测试的组件的代码:
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import ReactRouterPropTypes from 'react-router-prop-types';
import { Icon } from 'react-fa';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import MaterialIcon from 'material-ui/Icon';
import IconButton from 'material-ui/IconButton';
import Modal from 'material-ui/Modal';
import Hidden from 'material-ui/Hidden';
import SimpleButton from '../../common/SimpleButton';
import OutlineButton from '../../common/OutlineButton';
import * as sessionActions from '../../../actions/sessionActions';
import { APP_TITLE, LOGOUT, LOGIN, REGISTER } from '../../../constants/strings';
import { CHECKOUT } from '../../../constants/routes';
import styles from './styles';
import CartIcon from '../../common/Icons/Cart.svg';
import logo from '../../../images/logo.png';
import logoXs from '../../../images/logoXS.png';
import Login from '../Login';
import Register from '../Register';
import Wrapper from '../../common/Wrapper';
class Header extends Component {
constructor(props) {
super(props);
this.state = {};
}
handleLogoutClick = () => {
this.props.actions.logout();
};
handleOpenModal = (s) => {
this.setState({ openModal: s });
};
handleCloseModal = () => {
this.setState({ openModal: null });
};
handleCartIcon = () => {
this.props.history.push(CHECKOUT);
};
renderAuthenticated = () => (
<SimpleButton onClick={this.handleLogoutClick} className={this.props.classes.button}>
{LOGOUT}
</SimpleButton>
);
renderNotAuthenticated = () => {
const { classes, history } = this.props;
return (
<Fragment>
<SimpleButton onClick={() => this.handleOpenModal(LOGIN)} className={classes.button} id="btn-login-modal">
<Hidden smUp>
<Icon className={classes.icons} name="user-circle" alt="login" size="2x" />
</Hidden>
<Hidden xsDown>{LOGIN}</Hidden>
</SimpleButton>
<Modal open={this.state.openModal === LOGIN} onClose={this.handleCloseModal}>
<Login
history={history}
handleCloseModal={this.handleCloseModal}
handleChangeModal={this.handleOpenModal}
/>
</Modal>
<Hidden xsDown>
<OutlineButton
onClick={() => this.handleOpenModal(REGISTER)}
color="primary"
className={classes.button}
>
{REGISTER}
</OutlineButton>
<Modal open={this.state.openModal === REGISTER} onClose={this.handleCloseModal}>
<Register
history={history}
handleCloseModal={this.handleCloseModal}
handleChangeModal={this.handleOpenModal}
/>
</Modal>
</Hidden>
</Fragment>
);
};
render() {
const { authenticated, classes } = this.props;
return (
<AppBar position="static" color="default" className={classes.appBar}>
<Wrapper>
<Toolbar className={classes.toolBar}>
<div className={classes.flex}>
<Hidden smUp>
<img src={logoXs} alt={APP_TITLE} />
</Hidden>
<Hidden xsDown>
<img src={logo} alt={APP_TITLE} />
</Hidden>
</div>
{authenticated ? this.renderAuthenticated() : this.renderNotAuthenticated()}
<IconButton className={classes.button} onClick={() => this.handleCartIcon()}>
<MaterialIcon>
<img src={CartIcon} alt="cart" />
</MaterialIcon>
</IconButton>
</Toolbar>
</Wrapper>
</AppBar>
);
}
}
const { objectOf, any, bool } = PropTypes;
Header.propTypes = {
/* eslint-disable react/no-typos */
classes: objectOf(any).isRequired,
actions: objectOf(any).isRequired,
authenticated: bool.isRequired,
history: ReactRouterPropTypes.history.isRequired,
};
const mapDispatch = dispatch => ({
actions: bindActionCreators(sessionActions, dispatch),
});
const mapStateToProps = ({ session }) => ({
authenticated: session.authenticated,
checked: session.checked,
});
export default connect(mapStateToProps, mapDispatch)(withStyles(styles)(Header));
这是测试文件:
import React from 'react';
import { shallow } from 'enzyme';
import Header from './';
import configureStore from '../../../store/configureStore';
const store = configureStore();
const header = shallow(<Header store={store} />);
describe('<Header />', () => {
it('should open modal when clicking `SimpleButton`', () => {
console.log(header.dive().debug());
});
});
当我运行测试时,我得到了这个:
FAIL src/components/containers/Header/Header.test.js ● <Header /> › should open modal when clicking `SimpleButton`
TypeError: Cannot read property '200' of undefined
6 | padding: '10px 5px',
7 | boxShadow: `-webkit-box-shadow: 0px 4px 10px 0px ${
> 8 | theme.palette.gray[200]
9 | }; -moz-box-shadow: 0px 4px 10px 0px ${theme.palette.gray[200]}; box-shadow: 0px 4px 10px 0px ${
10 | theme.palette.gray[200]
11 | }`,
at styles (src/components/containers/Header/styles.js:8:7)
at Object.create (node_modules/material-ui/styles/getStylesCreator.js:31:35)
at WithStyles.attach (node_modules/material-ui/styles/withStyles.js:275:45)
at WithStyles.componentWillMount (node_modules/material-ui/styles/withStyles.js:205:16)
at ReactShallowRenderer._mountClassComponent (node_modules/enzyme-adapter-react-16/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:137:22)
at ReactShallowRenderer.render (node_modules/enzyme-adapter-react-16/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:102:14)
at node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:287:35
at withSetStateAllowed (node_modules/enzyme-adapter-utils/build/Utils.js:94:16)
at Object.render (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:286:68)
at new ShallowWrapper (node_modules/enzyme/build/ShallowWrapper.js:119:22)
at ShallowWrapper.wrap (node_modules/enzyme/build/ShallowWrapper.js:1648:16)
at ShallowWrapper.<anonymous> (node_modules/enzyme/build/ShallowWrapper.js:1718:26)
at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1620:25)
at ShallowWrapper.dive (node_modules/enzyme/build/ShallowWrapper.js:1710:21)
at Object.<anonymous> (src/components/containers/Header/Header.test.js:12:24)
我尝试使用mount,在MuiThemeProvider中使用帮助器createShallow或来自MaterialUI的createMount包装组件。 什么都行不通。
答案 0 :(得分:0)
检查您的标头导入 它应该是组件的路径而不是
import Header from './';
将其更改为
//Replace path with the actual location
import Header from './path/Header';
答案 1 :(得分:0)
AppBar需要一个muiTheme上下文,你可以提供给.dive()(见documentation)
这是我对渲染AppBar material-ui组件的Header组件的测试。
import React from "react";
import {shallow} from "enzyme";
import Header from "../";
describe("Header", () => {
it("should match the snapshot", () => {
const wrapper = shallow(<Header />);
// dive in AppBar
const wrappedComponents = wrapper.dive({
context: {
muiTheme: {
appBar: "",
zIndex: 0,
prepareStyles: () => {},
button: {
iconButtonSize: 0,
},
},
},
});
expect(wrappedComponents).toMatchSnapshot();
});
});