首页 文章

React Testing:React Shallow Rendering单元测试中的事件处理程序

提问于
浏览
11

背景

React Shallow Rendering tests

我正在尝试学习如何使用React Shallow Rendering TestUtil并测试通过,直到我向两者添加了 onClick 事件处理程序;似乎我在 Accordion.test.jsthis.toggle Accordian.js 中使用的 Accordion.toggle 函数必定存在一些差异......但我无法弄明白 .

问题

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

重现的步骤

4 回答

  • 1

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

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

    测试中的

    • Accordion.toggleAccordion 类的属性,而代码中的 this.toggleAccordion 类的实例的属性 - 所以在这种情况下,您要比较两个不同的东西 . 要在测试中访问'instance'方法,可以将 Accordion.toggle 替换为 Accordion.prototype.toggle . 如果它不是你的构造函数中的 this.toggle = this.toggle.bind(this); ,那将会有效 . 这引出了我们的第二点 .

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

    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>
    ]);
    

    至于你的第二次失败测试“点击时应该变为活动状态”:

    • 您尝试调用不存在的 result.props.onClick() . 你打算叫 result.props.children[0].props.onClick();

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

    result.props.onClick();
    

    现在应该说:

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

    请参阅"Fixing Broken setState()" on this pagethis react issue部分 .

  • 0

    Marcin Grzywaczewski写了一篇很棒的article,其中包含一个测试点击处理程序的解决方法,该处理程序适用于浅层渲染 .

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

    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' });
    }
    

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

    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');
    });
    
  • 3

    要测试 onClick 等用户事件,您必须使用 TestUtils.Simulate.click . Sadly

    现在无法使用具有浅层渲染的ReactTestUtils.Simulate,我认为应该遵循的问题应该是:https://github.com/facebook/react/issues/1445

  • 9

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

    我的组件:

    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>
    

    希望它有所帮助!

相关问题