首页 文章

测试React Modal组件

提问于
浏览
5

对不起,我一直在努力尝试通过点击按钮来关闭我的React Modal . Modal尽可能简单,我已经尝试了我能想到或发现的一切,但我仍然无法查询它的孩子 .

模态组件:

var React = require('react');
var Modal = require('react-bootstrap').Modal;
var Button = require('react-bootstrap').Button;

var MyModal = React.createClass({
  ...
  render: function() {
    return (
      <Modal className="my-modal-class" show={this.props.show}>
        <Modal.Header>
          <Modal.Title>My Modal</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          Hello, World!
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={this.props.onHide}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }
});

我的目标是测试单击“关闭”按钮是否在单击时触发 onHide() 函数 .

我的测试文件:

describe('MyModal.jsx', function() {
  it('tests the Close Button', function() {
    var spy = sinon.spy();
    var MyModalComponent = TestUtils.renderIntoDocument(
      <MyModal show onHide={spy}/>
    );

    // This passes
    TestUtils.findRenderedComponentWithType(MyModalComponent, MyModal);

    // This fails
    var CloseButton = TestUtils.findRenderedDOMComponentWithTag(MyModalComponent, 'button');

    // Never gets here
    TestUtils.Simulate.click(CloseButton);
    expect(spy.calledOnce).to.be.true;
  });
});

无论我尝试什么,我似乎无法找到关闭按钮 .

2 回答

  • 1

    我用React Base Fiddle (JSX)写了一个jsFiddle来找出测试中发生了什么(我创建了自己的'spy',它在调用时只是登录到控制台) .

    我发现你找不到你的按钮的原因是因为它不存在你可能想到的地方 .

    Bootstrap Modal Component<Modal/> )实际上包含在React-Overlays模态组件中(代码中名为 BaseModal ,来自here) . 这反过来呈现一个名为 Portal 的组件,其render method只返回 null . 您正在尝试查找渲染组件的 null 值 .

    由于模态没有被渲染为传统的React方式,React无法看到模态以便使用 TestUtils . 一个完全独立的 <div/> 子节点放在 document 主体中,这个新的 <div/> 用于构建模态 .

    因此,为了允许您使用React的 TestUtils 模拟单击(按钮上的单击处理程序仍然绑定到按钮的单击事件),您可以使用标准JS方法来搜索DOM . 设置您的测试如下:

    describe('MyModal.jsx', function() {
      it('tests the Close Button', function() {
        var spy = sinon.spy();
        var MyModalComponent = TestUtils.renderIntoDocument(
          <MyModal show onHide={spy}/>
        );
    
        // This passes
        TestUtils.findRenderedComponentWithType(MyModalComponent, MyModal);
    
        // This will get the actual DOM node of the button
        var closeButton = document.body.getElementsByClassName("my-modal-class")[0].getElementsByClassName("btn btn-default")[0];
    
        // Will now get here
        TestUtils.Simulate.click(CloseButton);
        expect(spy.calledOnce).to.be.true;
      });
    });
    

    函数 getElementsByClassName 返回该类的元素集合,因此您必须从每个集合中获取第一个元素(在测试用例中,您唯一的元素) .

    您的测试现在应该通过^ _ ^

  • 7

    这是我最终选择的解决方案 . 它将React渲染模态的方式存储为仅渲染 <div> .

    test-utils.js

    var sinon = require('sinon');
    var React = require('react');
    var Modal = require('react-bootstrap').Modal;
    
    module.exports = {
      stubModal: function() {
        var createElement = React.createElement;
        modalStub = sinon.stub(React, 'createElement', function(elem) {
          return elem === Modal ?
            React.DOM.div.apply(this, [].slice.call(arguments, 1)) :
            createElement.apply(this, arguments);
        });
        return modalStub;
      },
      stubModalRestore: function() {
        if (modalStub) {
          modalStub.restore();
          modalStub = undefined;
        } else {
          console.error('Cannot restore nonexistent modalStub');
        }
      }
    };
    

    modal-test.jsx

    var testUtils = require('./test-utils');
    
    describe('test a Modal!', function() {
      before(testUtils.stubModal);
      after(testUtils.stubModalRestore);
    
      it('renders stuff', function() {
        var MyModalComponent = TestUtils.renderIntoDocument(
          <MyModal show/>
        );
        // Do more stuff you normally expect you can do
      });
    });
    

相关问题