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

11

背景

React Shallow Rendering tests

我正在试图学习如何使用 React 浅层渲染 TestUtil,并且测试已经通过,直到我向两者都添加了 onClick 事件处理程序。看起来我正在尝试在 Accordion.test.js 中使用的 Accordion.toggle 函数与 Accordian.js 中的 this.toggle 存在一些差异...但是我无法弄清楚。

问题

我如何使 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个回答

8

有若干问题导致你的测试无法通过。

针对测试 "应默认处于非活动状态" 进行分析:

  1. Accordion.toggle in your test is a property of the Accordion class, and this.toggle in your code is a property of a instance of the Accordion class - so in this case you are comparing two different things. To access the 'instance' method in your test you could replace Accordion.toggle with Accordion.prototype.toggle. Which would work if it were not for this.toggle = this.toggle.bind(this); in your constructor. Which leads us to the second point.

  2. When you call .bind() on a function it creates a new function at runtime - so you can't compare it to the original Accordion.prototype.toggle. The only way to work around this is to pull the "bound" function out of the result from render:

    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. You try calling result.props.onClick() which does not exist. You meant to call result.props.children[0].props.onClick();

  2. There is a bug in React that requires a global "document" variable to be declared when calling setState with shallow rendering - how to work around this in every circumstance is beyond the scope of this question, but a quick work around to get your tests passing is to add global.document = {}; right before you call the onClick method. In other words where your original test had:

    result.props.onClick();
    

    Should now say:

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

    See the section "Fixing Broken setState()" on this page and this react issue.


3

Marcin Grzywaczewski撰写了一篇很棒的文章,其中介绍了一种使用浅渲染测试点击处理程序的方法。

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

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属性的函数值,将事件对象放在桩中:
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');
});

1

0

我已成功测试了我的无状态组件中的点击事件。这是我的做法:

我的组件:

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>

希望它有所帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接