在 Jest 中测试 React 单击事件失败,因为无法应用 Jquery - 我该如何测试它?

Testing React click event in Jest fails because the Jquery can't be applied - How can I test it?

我有一个像这样的 React class

var React = require('react'),
    $ = require('jquery'),
    AccordionStep = require('./accordion-step');

var Accordion = React.createClass({

  toggleFooter: function(e) {
    var $target = $(e.target),
        $parent = $target.parents('.project-container');

    $target.toggleClass('up down');
    $parent.find('.project-accordion').toggleClass('active');
  },

  render: function() {
    return (
      <div>
        <ul className="project-accordion">
          {this.props.steps.map(function(step, i){
            return <AccordionStep step={step} key={i}/>
          })}
        </ul>
        <span className="footer-info">{this.props.completedSteps} of {this.props.totalSteps} steps completed</span>
        <span className="arrow down mt1" onClick={this.toggleFooter}></span>
      </div>
    )
  }
});

module.exports = Accordion;

我还有一个 Jest 测试文件,用于检查单击箭头时 class 是否被正确切换。

jest.dontMock('../../../dashboard/projects/accordion')
    .dontMock('../../fixtures/projects.fixtures')
    .dontMock('jquery');

describe('Accordion', function() {
  var $ = require('jquery'),
      React = require('react/addons'),
      Accordion = require('../../../dashboard/projects/accordion'),
      AccordionStep = require('../../../dashboard/projects/accordion-step'),
      ProjectFixtures = require('../../fixtures/projects.fixtures'),
      TestUtils = React.addons.TestUtils;

  describe('render', function() {
    var accordion,
        projectFixtures = ProjectFixtures().projects[0],
        steps = projectFixtures.steps;

    beforeEach(function() {
      accordion = TestUtils.renderIntoDocument(
        <div className="project-container">
          <Accordion steps={steps} 
                     completedSteps={projectFixtures.completedSteps} 
                     totalSteps={projectFixtures.totalSteps} />
        </div>
      );
    });

    describe('clicking the arrow icon', function(){
      var arrow;

      beforeEach(function() {
        arrow = TestUtils.findRenderedDOMComponentWithClass(accordion, 'arrow');
      });

      it('should change the arrow to point up when it was clicked', function() {
        TestUtils.Simulate.click(arrow);

        expect(arrow.props.className).toEqual('arrow up mt1');
      });

    });

  });

});

现在我一直在控制台记录 toggleFooter 函数中发生的事情,我知道该函数可以正常工作。 classes 已切换,但测试仍然失败。

有什么办法可以测试按钮的行为吗?我想这个问题与测试实际呈现测试的方式有关 DOM。我尝试使用 jQuery 断言 classes 已正确切换,但这也不起作用(我假设是由于上述原因)。

任何帮助将不胜感激。

您正在直接通过 $target.toggleClass('up down'); 编辑 .arrow dom 节点的 className 属性,而不是生成它的 ReactComponent 的道具。

在您的代码中,arrow 是一个 ReactComponent,而不是 DOM 节点。要找到 ReactComponent 的 DOM 节点,请使用 React.findDOMNode(component).

React 的方法是放弃 jQuery 来完成这样一个微不足道的任务,而是用一个指示手风琴是否处于活动状态的标志来更新您的组件状态。

getInitialState: function() {
  return {
    accordionActive: false
  };
},

toggleFooter: function(e) {
  this.setState({
    accordionActive: !this.state.accordionActive
  });
},

render: function() {
  return (
    <div>
      <ul className={'project-accordion' + (this.state.accordionActive ? ' active' : '')}>
        {this.props.steps.map(function(step, i){
          return <AccordionStep step={step} key={i}/>
        })}
      </ul>
      <span className="footer-info">{this.props.completedSteps} of {this.props.totalSteps} steps completed</span>
      <span className={'arrow mt1 ' + (this.state.accordionActive ? 'up' : 'down')} onClick={this.toggleFooter}></span>
    </div>
  );
}

使用classNames模块,你可以用

替换那些丑陋的className计算
className={classNames('project-accordion', this.state.accordionActive && 'active')}

className={classNames('arrow mt1', this.state.accordionActive ? 'up' : 'down')}

arrow.props.className 的值应始终为 arrow mt1 uparrow mt1 down