首页 > 解决方案 > 单击处理程序模拟函数不会被调用

问题描述

我要测试的组件:

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]

但它没有被调用

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

编辑: 我发现了如何使测试通过: In Pad.js,还导出未包装的组件:

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

并且在测试中,使用展开的组件而不是连接的组件。

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

标签: javascriptreactjsreduxjestjsenzyme

解决方案


似乎您将处理程序传递给容器,而不是组件。每当您模拟单击时,这就是映射到被调用组件的 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),
  ]);
});

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

例如const mapStateToProps = (state, ownProps) => ({ value: ownProps.value});

希望这可以帮助!


推荐阅读