Fix rendering into shadow root (#11037)

* Replace skipped unit test with a fixture

* Fix crash for custom elements
This commit is contained in:
Dan Abramov
2017-10-02 20:50:14 +01:00
committed by GitHub
parent bbb272f3aa
commit 8b4ec79d4f
6 changed files with 69 additions and 6424 deletions
+1
View File
@@ -62,6 +62,7 @@ class Header extends React.Component {
<option value="/date-inputs">Date Inputs</option>
<option value="/error-handling">Error Handling</option>
<option value="/event-pooling">Event Pooling</option>
<option value="/custom-elements">Custom Elements</option>
</select>
</label>
<label htmlFor="react_version">
@@ -0,0 +1,47 @@
import FixtureSet from '../../FixtureSet';
import TestCase from '../../TestCase';
const React = window.React;
const ReactDOM = window.ReactDOM;
class HelloWorld extends React.Component {
render() {
return <h1>Hello, world!</h1>;
}
}
// Babel breaks web components.
// https://github.com/w3c/webcomponents/issues/587
// eslint-disable-next-line no-new-func
const MyElement = new Function(
'React',
'ReactDOM',
'HelloWorld',
`
return class MyElement extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode:'open' });
ReactDOM.render(React.createElement(HelloWorld), shadowRoot);
}
}`
)(React, ReactDOM, HelloWorld);
customElements.define('my-element', MyElement);
export default class ButtonTestCases extends React.Component {
render() {
return (
<FixtureSet
title="Custom Elements"
description="Support for Custom Element DOM standards.">
<TestCase title="Rendering into shadow root">
<TestCase.ExpectedResult>
You should see "Hello, World" printed below.{' '}
</TestCase.ExpectedResult>
<my-element />
</TestCase>
</FixtureSet>
);
}
}
@@ -9,6 +9,7 @@ import ButtonFixtures from './buttons';
import DateInputFixtures from './date-inputs';
import ErrorHandling from './error-handling';
import EventPooling from './event-pooling';
import CustomElementFixtures from './custom-elements';
const React = window.React;
@@ -40,6 +41,8 @@ function FixturesPage() {
return <ErrorHandling />;
case '/event-pooling':
return <EventPooling />;
case '/custom-elements':
return <CustomElementFixtures />;
default:
return <p>Please select a test fixture.</p>;
}
File diff suppressed because it is too large Load Diff
+18 -11
View File
@@ -163,17 +163,24 @@ var DOMRenderer = ReactFiberReconciler({
getRootHostContext(rootContainerInstance: Container): HostContext {
let type;
let namespace;
if (rootContainerInstance.nodeType === DOCUMENT_NODE) {
type = '#document';
let root = (rootContainerInstance: any).documentElement;
namespace = root ? root.namespaceURI : getChildNamespace(null, '');
} else {
const container: any = rootContainerInstance.nodeType === COMMENT_NODE
? rootContainerInstance.parentNode
: rootContainerInstance;
const ownNamespace = container.namespaceURI || null;
type = container.tagName;
namespace = getChildNamespace(ownNamespace, type);
const nodeType = rootContainerInstance.nodeType;
switch (nodeType) {
case DOCUMENT_NODE:
case DOCUMENT_FRAGMENT_NODE: {
type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment';
let root = (rootContainerInstance: any).documentElement;
namespace = root ? root.namespaceURI : getChildNamespace(null, '');
break;
}
default: {
const container: any = nodeType === COMMENT_NODE
? rootContainerInstance.parentNode
: rootContainerInstance;
const ownNamespace = container.namespaceURI || null;
type = container.tagName;
namespace = getChildNamespace(ownNamespace, type);
break;
}
}
if (__DEV__) {
const validatedTag = type.toLowerCase();
@@ -17,7 +17,6 @@ var React;
var ReactDOM;
var ReactDOMServer;
var ReactTestUtils;
var WebComponents;
describe('ReactMount', () => {
beforeEach(() => {
@@ -27,16 +26,6 @@ describe('ReactMount', () => {
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
ReactTestUtils = require('react-dom/test-utils');
try {
if (WebComponents === undefined && typeof jest !== 'undefined') {
WebComponents = require('WebComponents');
}
} catch (e) {
// Parse error expected on engines that don't support setters
// or otherwise aren't supportable by the polyfill.
// Leave WebComponents undefined.
}
});
describe('unmountComponentAtNode', () => {
@@ -201,29 +190,6 @@ describe('ReactMount', () => {
);
});
if (WebComponents !== undefined) {
it('should allow mounting/unmounting to document fragment container', () => {
var shadowRoot;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
shadowRoot = this.createShadowRoot();
ReactDOM.render(<div>Hi, from within a WC!</div>, shadowRoot);
expect(shadowRoot.firstChild.tagName).toBe('DIV');
ReactDOM.render(<span>Hi, from within a WC!</span>, shadowRoot);
expect(shadowRoot.firstChild.tagName).toBe('SPAN');
},
},
});
proto.unmount = function() {
ReactDOM.unmountComponentAtNode(shadowRoot);
};
document.registerElement('x-foo', {prototype: proto});
var element = document.createElement('x-foo');
element.unmount();
});
}
it('should warn if render removes React-rendered children', () => {
var container = document.createElement('container');