React 测试:React 浅渲染单元测试中的事件处理程序

IT技术 javascript unit-testing testing reactjs mocha.js
2021-05-07 04:50:17

背景

react浅渲染测试

我正在尝试学习如何使用 React Shallow Rendering TestUtil 并通过测试,直到我onClick向两者添加了事件处理程序;似乎Accordion.toggle我试图在Accordion.test.jsthis.togglein 中使用函数有一些不同Accordian.js......但我想不通。

问题

如何让两个突出显示的测试Accordian.test.js通过?

重现步骤

  1. 克隆https://github.com/trevordmiller/shallow-rendering-testing-playground
  2. npm install
  3. npm run dev - 当您单击“Lorem Ipsum”时,可以看到该组件正在运行
  4. npm run test:watch - 看到测试失败
4个回答

有许多问题会阻止您的测试通过。

查看测试“默认情况下应该处于非活动状态”:

  1. Accordion.toggle在您的测试中是Accordion的属性,而this.toggle在您的代码中是Accordion的实例的属性- 所以在这种情况下,您正在比较两个不同的东西。要访问测试中的“实例”方法,您可以将其替换Accordion.toggleAccordion.prototype.toggle. 如果不是this.toggle = this.toggle.bind(this);在您的构造函数中,这将起作用这将我们引向第二点。

  2. 当您在函数上调用 .bind() 时,它会在运行时创建一个新函数 - 因此您无法将其与原始 .bind() 进行比较Accordion.prototype.toggle解决此问题的唯一方法是从渲染结果中提取“绑定”函数:

    let toggle = result.props.children[0].props.onClick;
    
    assert.deepEqual(result.props.children, [
      <a onClick={toggle}>This is a summary</a>,
      <p style={{display: 'none'}}>This is some details</p>
    ]);
    

至于您的第二个失败测试“单击时应变为活动状态”:

  1. 您尝试调用result.props.onClick()不存在的方法。你想打电话result.props.children[0].props.onClick();

  2. React 中存在一个错误,需要在使用浅渲染调用 setState 时声明全局“文档”变量 - 如何在每种情况下解决此问题超出了本问题的范围,但可以快速解决让您的测试通过是global.document = {};在调用 onClick 方法之前添加换句话说,您的原始测试有:

    result.props.onClick();
    

    现在应该说:

    global.document = {};
    result.props.children[0].props.onClick();
    

    请参阅此页面上的“修复损坏的 setState()”部分此react问题

Marcin Grzywaczewski写了一篇很棒的文章,其中包含一种用于测试使用浅渲染的点击处理程序的变通方法。

给定一个带有onClickprop的嵌套元素和一个上下文绑定到组件的处理程序:

render() {
  return (
    <div>
      <a className="link" href="#" onClick={this.handleClick}>
        {this.state.linkText}
      </a>
      <div>extra child to make props.children an array</div>
    </div>
  );
}

handleClick(e) {
  e.preventDefault();
  this.setState({ linkText: 'clicked' });
}

您可以手动调用onClickprop的函数值,在事件对象中存根:

it('updates link text on click', () => {
  let tree, link, linkText;

  const renderer = TestUtils.createRenderer();
  renderer.render(<MyComponent />);

  tree = renderer.getRenderOutput();
  link = tree.props.children[0];
  linkText = link.props.children;

  // initial state set in constructor
  expect(linkText).to.equal('Click Me');

  // manually invoke onClick handler via props
  link.props.onClick({ preventDefault: () => {} });

  tree = renderer.getRenderOutput();
  link = tree.props.children[0];
  linkText = link.props.children;

  expect(linkText).to.equal('Clicked');
});

为了测试用户事件,就像onClick你必须使用TestUtils.Simulate.click. 可悲的是

现在不可能将 ReactTestUtils.Simulate 与浅渲染一起使用,我认为要遵循的问题应该是:https : //github.com/facebook/react/issues/1445

我已经在我的无状态组件中成功测试了我的点击。方法如下:

我的组件:

import './ButtonIcon.scss';

import React from 'react';
import classnames from 'classnames';

const ButtonIcon = props => {
  const {icon, onClick, color, text, showText} = props,
    buttonIconContainerClass = classnames('button-icon-container', {
      active: showText
    });

  return (
    <div
      className={buttonIconContainerClass}
      onClick={onClick}
      style={{borderColor: color}}>
      <div className={`icon-container ${icon}`}></div>
      <div
        className="text-container"
        style={{display: showText ? '' : 'none'}}>{text}</div>
    </div>
  );
}

ButtonIcon.propTypes = {
  icon: React.PropTypes.string.isRequired,
  onClick: React.PropTypes.func.isRequired,
  color: React.PropTypes.string,
  text: React.PropTypes.string,
  showText: React.PropTypes.bool
}

export default ButtonIcon;

我的测试:

it('should call onClick prop when clicked', () => {
  const iconMock = 'test',
    clickSpy = jasmine.createSpy(),
    wrapper = ReactTestUtils.renderIntoDocument(<div><ButtonIcon icon={iconMock} onClick={clickSpy} /></div>);

  const component = findDOMNode(wrapper).children[0];

  ReactTestUtils.Simulate.click(component);

  expect(clickSpy).toHaveBeenCalled();
  expect(component).toBeDefined();
});

重要的是包装组件:

<div><ButtonIcon icon={iconMock} onClick={clickSpy} /></div>

希望有帮助!