我正在尝试测试一个呈现iframe并将标记直接注入(inject)该iframe的React组件。 (我不是要在iframe中加载网址。)

该组件实际上在浏览器中可以很好地工作,但是到目前为止,为它编写测试似乎是不可能的。我不知道为什么。

这是一个简短的测试案例,可以证明失败。



    // Set up DOM
    var jsdom = require( 'jsdom' ).jsdom;
    global.document = jsdom( '' );
    global.window = document.defaultView;
    global.navigator = document.defaultView.navigator;

    // Prepare React
    var ReactTestUtils = require( 'react-addons-test-utils' );
    var React = require( 'react' );

    var Frame = React.createClass( {
      componentDidMount() {
        console.log( 'iframe loaded. adding content' );
        const iframe = this.refs.iframe;
        console.log( 'adding content to', iframe.contentWindow ); // Should not be null
        iframe.contentWindow.document.open();
        iframe.contentWindow.document.write( 'Hello World!' );
        iframe.contentWindow.document.close();
      },

      render() {
        console.log( 'rendering iframe' );
        return React.createElement( 'iframe', { ref: 'iframe' } );
      }
    } );

    // Render the component
    ReactTestUtils.renderIntoDocument( React.createElement( Frame ) );


要运行此程序,您需要安装以下npm软件包:jsdom,react,react-addons-test-utils。然后,您应该可以使用node运行上面的代码。

最佳答案

我对您的代码进行了彻底的测试,最终发现问题是ReactTestUtils.renderIntoDocument
ReactTestUtils.renderIntoDocument为该组件创建一个容器,但不再附加到DOM(因此),因此contentWindow元素的iframe为什么为null。如果您在ReactTestUtils来源中阅读注释,您会发现他们正在考虑重命名renderIntoDocument,因为从技术上讲,它不是!
看来,解决方案是直接使用ReactDOM代替。

以下是ReactTestUtils源代码:

var ReactTestUtils = {
  renderIntoDocument: function (instance) {
    var div = document.createElement('div');
    // None of our tests actually require attaching the container to the
    // DOM, and doing so creates a mess that we rely on test isolation to
    // clean up, so we're going to stop honoring the name of this method
    // (and probably rename it eventually) if no problems arise.
    // document.documentElement.appendChild(div);
    return ReactDOM.render(instance, div);
  },
 }

在测试用例中使用ReactDOM可以工作:
// Set up DOM
var jsdom = require( 'jsdom' ).jsdom;
global.document = jsdom( '' );
global.window = document.defaultView;
global.navigator = document.defaultView.navigator;

// Prepare React
var ReactTestUtils = require( 'react-addons-test-utils' );
var React = require( 'react' );
var ReactDOM = require('react-dom')

var Frame = React.createClass( {
  componentDidMount() {
    console.log( 'iframe loaded. adding content' );
    const iframe = this.refs.iframe;

    console.log( 'adding content to', iframe.contentWindow ); // Should not be null
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write( 'Hello World!' );
    iframe.contentWindow.document.close();

    // Should log "Hello World!"
    console.log(iframe.contentWindow.document.body.innerHTML);
  },

  render() {
    console.log( 'rendering iframe' );
    return React.createElement( 'iframe', { ref: 'iframe' } );
  }
} );

// Render the component

// NOPE
//ReactTestUtils.renderIntoDocument( React.createElement( Frame ) );

// YUP
ReactDOM.render(React.createElement(Frame), document.body)

遗憾的是,此文档未在ReactTestUtils中提及。

10-07 17:24