【问题标题】:Testing a React Modal component测试一个 React Modal 组件
【发布时间】:2016-01-29 13:55:28
【问题描述】:

很抱歉,我一直在尝试通过单击按钮来关闭我的 React 模式。 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;
  });
});

无论我怎么尝试,我似乎都找不到关闭按钮。

【问题讨论】:

  • 你在开玩笑吗?我从未使用过 jest,但我认为它会自动模拟依赖组件。这可能是问题吗?
  • @AbhishekJain 我正在使用摩卡
  • &lt;Button&gt; 一个用户定义的类还是你想要做&lt;button&gt;
  • @HenrikAndersson 我应该澄清这是 React-Bootstrap 的一部分

标签: javascript unit-testing reactjs bootstrap-modal react-jsx


【解决方案1】:

我使用React Base Fiddle (JSX) 写了一个jsFiddle 来了解您的测试中发生了什么(我创建了自己的“间谍”,它在被调用时简单地登录到控制台)。

我发现您找不到按钮的原因是它不存在于您可能期望的位置。

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

由于模态不是以传统的 React 方式呈现的,React 看不到模态以使用TestUtils on。一个完全独立的&lt;div/&gt; 子节点放置在document 主体中,这个新的&lt;div/&gt; 用于构建模式。

所以,为了让您可以使用 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 返回具有该类的元素集合,因此您必须从每个集合中获取第一个(在您的测试用例中,是您唯一的一个)。

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

【讨论】:

  • findRenderedDOMComponentWithTag 失败,因为它找到 0 而不是 1 :(
  • 哦不!我以为我拥有它!我暂时把它留在这里,但我会继续努力。当我发现新的东西时,我会编辑我的答案=)
  • 我已经用新的解决方案更新了我的答案。如果您有任何问题,请告诉我 =)
  • 我遇到了几乎相同的问题,这个解决方案对我有用。它应该被标记为正确的 IMO。
  • 这行得通!我花了 2 个小时试图弄清楚我的测试出了什么问题。谢谢你的解释!
【解决方案2】:

这是我最终采用的解决方案。它将 React 渲染 Modal 的方式存根,改为仅渲染 &lt;div&gt;

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

【讨论】:

    猜你喜欢
    • 2019-03-29
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 2016-01-30
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多