最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does rendering an iframe into jsdom with ReactTestUtils not provide a contentWindow? - Stack Overflow

programmeradmin2浏览0评论

I'm trying to test a React ponent that renders an iframe and injects markup directly into that iframe. (I'm not trying to load a URL in the iframe.)

The ponent actually works quite well in a browser, but writing a test for it so far seems to be impossible. I'm not sure why.

Here is a shortened test case which proves the failure.



    // 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( {
      ponentDidMount() {
        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 ponent
    ReactTestUtils.renderIntoDocument( React.createElement( Frame ) );

To run this, you'll need the following npm packages installed: jsdom, react, react-addons-test-utils. You should be able to then run the above code using node.

I'm trying to test a React ponent that renders an iframe and injects markup directly into that iframe. (I'm not trying to load a URL in the iframe.)

The ponent actually works quite well in a browser, but writing a test for it so far seems to be impossible. I'm not sure why.

Here is a shortened test case which proves the failure.



    // 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( {
      ponentDidMount() {
        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 ponent
    ReactTestUtils.renderIntoDocument( React.createElement( Frame ) );

To run this, you'll need the following npm packages installed: jsdom, react, react-addons-test-utils. You should be able to then run the above code using node.

Share Improve this question asked Mar 16, 2016 at 0:17 Payton SwickPayton Swick 5901 gold badge6 silver badges9 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

I tested your code pretty thoroughly and ended up finding the issue to be ReactTestUtils.renderIntoDocument.

ReactTestUtils.renderIntoDocument creates a container for the Component, but doesn't attach to the DOM (anymore), thus why contentWindow will be null for iframe elements. If you read the ments in the ReactTestUtils source you'll notice they are considering renaming renderIntoDocument because technically it doesn't! The solution, it seems, is to use directly ReactDOM instead.

Here is a bit of code from the ReactTestUtils source:

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

Using ReactDOM with your test case works:

// 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( {
  ponentDidMount() {
    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 ponent

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

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

It's too bad that this isn't mentioned in the docs for ReactTestUtils.

You need to append the iframe to your document before contentWindow will bee available.

Check this code:

var iframe = document.createElement('iframe');
console.log(iframe.contentWindow);

document.body.appendChild(iframe);

console.log(iframe.contentWindow);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论