由于样式,MaterialUI测试失败

时间:2018-03-12 16:58:32

标签: reactjs material-ui jestjs enzyme

我尝试使用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包装组件。 什么都行不通。

2 个答案:

答案 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();
  });
});