单击处理程序模拟函数不会被调用

时间:2018-06-11 12:11:50

标签: javascript reactjs redux jestjs enzyme

我要测试的组件:

import React from 'react';
import { connect } from 'react-redux';
import { actionCreators as calculatorActionCreators } from './calculator';

class Pad extends React.Component {
  handleClick = () => {
    this.props.add(this.props.value);
  };
  render() {
    return (
      <div className="pad" onClick={this.handleClick}>
        {this.props.display}
      </div>
    );
  }
}

const mapStateToProps = state => ({});
const mapDispatchToProps = dispatch => ({
  add: val => dispatch(calculatorActionCreators.addExpression(val)),
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Pad);

测试:

import React from 'react';
import store from './store';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

import Pad from './Pad';
it('adds calculation steps', () => {
  const mockAdd = jest.fn();
  const value = 1;
  const element = mount(
    <Pad
      store={store}
      value={value}
      add={mockAdd}
    />
  );
  const clickable = element.find('.pad');
  clickable.simulate('click');
  expect(mockAdd).toHaveBeenCalledWith(value);
});

我希望.pad元素上的模拟点击会调用handleClick,因此this.props.add会被调用。但是当我运行测试时,我收到了这个错误:

  

已调用的预期模拟函数:   [1]

     

但它没有被称为

当我手动测试应用程序时,该应用程序正常工作,所以我想我尝试测试它的方式有问题。

修改 我发现了如何通过测试: 在Pad.js中,还要导出未包装的组件:

export class UnwrappedPad extends React.Component {
    ...
}
...
export default connect(mapStateToProps, mapDispatchToProps)(UnwrappedPad);

在测试中,使用未包装的组件而不是连接的组件。

我仍然不明白为什么在connect中包装它时它不起作用。

1 个答案:

答案 0 :(得分:2)

好像您将处理程序传递给容器,而不是传递给组件。每当您模拟单击时,这是映射到被调用的组件的props的方法。

所以你有两种可能性。

1)Redux可以帮助您从行为中分离演示文稿,这样您就可以提取您的演示组件并单独测试它。您的测试可能类似于:

it('adds calculation steps', () => {
  const mockAdd = jest.fn();
  const value = 1;
  const element = mount(<Pad value={value} add={mockAdd}/>);
  const clickable = element.find('.pad');

  clickable.simulate('click');

  expect(mockAdd).toHaveBeenCalledWith(value);
});

你的组件是这样的:

export class Pad extends React.Component {

  handleClick = () => {
    this.props.add(this.props.value);
  };

  render() {
    return (
      <div className="pad" onClick={this.handleClick}>
        {this.props.display}
      </div>
    );
  }
}

2)如果你真的想测试集成组件和容器,那么你可以使用像redux-mock-store这样的东西。这将允许您验证通过调度程序触发的操作。你测试可能看起来像这样:

it('adds calculation steps', () => {
  const mockStore = configureStore([])
  const store = mockStore({})
  const value = 1;
  const element = mount(
    <Provider store={store}>
      <Pad value={value}/>
    </Provider>
  );

  const clickable = element.find('.pad');

  clickable.simulate('click');

  expect(store.getActions()).toHaveBeenCalledWith([
    calculatorActionCreators.addExpression(val),
  ]);
});

还有来自redux的mapStateToProps方法得到第二个参数,它们是容器的自己的porps。然后我会明确表示该值是通过的。

e.g。 const mapStateToProps = (state, ownProps) => ({ value: ownProps.value});

希望这有帮助!