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 badges2 Answers
Reset to default 4I 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);