@samitouri / QOS-React-2 / commits / 9459bad912

Run test script and fix regressions

Fixes the case where there's an uncaught error and the root unmounts. We implement this by rendering the root as if its child is null. Null is not usually allowed at the top level, so we need to special case it.

Andrew Clark committed Jan 12, 2017 at 10:50 UTC 9459bad9128e35a13aea82bbae4f206c4498bb58
7 files changed +23 -12
scripts/fiber/tests-failing.txt
-4
@@ -64,10 +64,6 @@ src/renderers/shared/shared/__tests__/ReactEmptyComponent-test.js
64 src/renderers/shared/shared/__tests__/ReactMultiChildText-test.js
65 * should reorder keyed text nodes
66
67 -src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js
68 -* should warn when stateless component returns array
69 -* should warn when using non-React functions in JSX
70 -
67 src/renderers/shared/shared/__tests__/ReactUpdates-test.js
68 * marks top-level updates
69
scripts/fiber/tests-passing.txt
+3
@@ -544,6 +544,8 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
544 * should bubble events from the portal to the parent
545 * should not onMouseLeave when staying in the portal
546 * should not crash encountering low-priority tree
547 +* throws if non-element passed to top-level render
548 +* throws if something other than false, null, or an element is returned from render
549
550 src/renderers/dom/shared/__tests__/CSSProperty-test.js
551 * should generate browser prefixes for its `isUnitlessNumber`
@@ -1536,6 +1538,7 @@ src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js
1538 * should update stateless component
1539 * should unmount stateless component
1540 * should pass context thru stateless component
1541 +* should throw when stateless component returns undefined
1542 * should throw on string refs in pure functions
1543 * should warn when given a string ref
1544 * should warn when given a function ref
src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
+6 -4
@@ -1015,8 +1015,10 @@ describe('ReactDOMFiber', () => {
1015 });
1016
1017 it('throws if non-element passed to top-level render', () => {
1018 + // FIXME: These assertions pass individually, but they leave React in
1019 + // an inconsistent state. This suggests an error-handling bug. I'll fix
1020 + // this in a separate PR.
1021 const message = 'render(): Invalid component element.';
1019 -
1022 expect(() => ReactDOM.render(null, container)).toThrow(message, container);
1023 expect(() => ReactDOM.render(undefined, container)).toThrow(message, container);
1024 expect(() => ReactDOM.render(false, container)).toThrow(message, container);
@@ -1030,9 +1032,9 @@ describe('ReactDOMFiber', () => {
1032 return props.children;
1033 }
1034
1033 - expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/Render\.render/);
1034 - expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/Render\.render/);
1035 - expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/Render\.render/);
1035 + expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/You may have returned undefined/);
1036 + expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/You may have returned undefined/);
1037 + expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/You may have returned undefined/);
1038 });
1039 });
1040 }
src/renderers/shared/fiber/ReactChildFiber.js
+5 -2
@@ -75,6 +75,7 @@ const {
75 NoEffect,
76 Placement,
77 Deletion,
78 + Err,
79 } = ReactTypeOfSideEffect;
80
81 function coerceRef(current: ?Fiber, element: ReactElement) {
@@ -1129,7 +1130,9 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1130 if (returnFiber.tag === HostRoot) {
1131 // Top-level only accepts elements or portals
1132 invariant(
1132 - false,
1133 + // If the root has an error effect, this is an intentional unmount.
1134 + // Don't throw an error.
1135 + returnFiber.effectTag & Err,
1136 'render(): Invalid component element.'
1137 );
1138 } else {
@@ -1247,7 +1250,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
1250 const Component = returnFiber.type;
1251 invariant(
1252 false,
1250 - '%s: Nothing was returned from render. This usually means a ' +
1253 + '%s(...): Nothing was returned from render. This usually means a ' +
1254 'return statement is missing. Or, to render nothing, ' +
1255 'return null.',
1256 Component.displayName || Component.name || 'Component'
src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+1
@@ -956,6 +956,7 @@ describe('ReactIncremental', () => {
956
957 function Trail() {
958 ops.push('Trail');
959 + return null;
960 }
961
962 function App(props) {
src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
+1
@@ -496,6 +496,7 @@ describe('ReactIncrementalErrorHandling', () => {
496 if (props.throw) {
497 throw new Error('Hello');
498 }
499 + return null;
500 }
501
502 function Foo() {
src/renderers/shared/shared/__tests__/ReactStatelessComponent-test.js
+7 -2
@@ -146,8 +146,13 @@ describe('ReactStatelessComponent', () => {
146 expect(function() {
147 ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
148 }).toThrowError(
149 - 'NotAComponent(...): A valid React element (or null) must be returned. ' +
150 - 'You may have returned undefined, an array or some other invalid object.'
149 + ReactDOMFeatureFlags.useFiber ?
150 + // Fiber gives a more specific error message for undefined because it
151 + // supports more return types.
152 + 'NotAComponent(...): Nothing was returned from render' :
153 + // Stack's message is generic.
154 + 'NotAComponent(...): A valid React element (or null) must be returned. ' +
155 + 'You may have returned undefined, an array or some other invalid object.'
156 );
157 });
158