Testing a React Modal component

这一生的挚爱 提交于 2019-12-06 03:57:28

问题


I'm sorry, but I've been having the toughest time trying to test closing my React Modal by clicking a button. The Modal is as simple as can be, and I've tried everything I can think of or find, but I still can't query its children.

The Modal component:

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

My goal is to test if that Close button fires the onHide() function when it is clicked.

My test file:

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

No matter what I try, I can't seem to find the Close Button.


回答1:


I wrote a jsFiddle using the React Base Fiddle (JSX) to find out what was going on in your test (I created my own 'spy' that simply logged to the console when called).

I found out that the reason you can't find your button is because it doesn't exist where you might expect it to.

The Bootstrap Modal Component (<Modal/>) is actually contained within a React-Overlays modal component (called BaseModal in the code, which is from here). This in turn renders a component called Portal whose render method simply returns null. It is this null value you are trying to find rendered components on.

Due to the modal not being rendered the traditional React way, React cannot see the modal in order to use TestUtils on. An entirely seperate <div/> child node is placed in the document body and this new <div/> is used to build the modal.

So, in order to allow you to simulate a click using React's TestUtils (the click handler on the button is still bound to the button's click event), you can use standard JS methods to search the DOM instead. Set up your test as follows:

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

The function getElementsByClassName returns a collection of elements with that class so you must take the first one (and in your test case, your only one) from each collection.

Your test should now pass ^_^




回答2:


This is the solution I ended up going with. It stubs the way React renders a Modal to just render a <div> instead.

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


来源:https://stackoverflow.com/questions/35086297/testing-a-react-modal-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!