Make disableNewFiberFeatures = true the default when runnings tests

This exposed a few more cases that I missed.
This commit is contained in:
Andrew Clark committed 2017-01-25 11:52:48 -08:00
1 parent 5c4362dc5c
commit c0e5df66ec
17 files changed
+148 -92

No files matched your search

-1
View File
@@ -554,7 +554,6 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
* should not crash encountering low-priority tree
* throws if non-element passed to top-level render
* throws if something other than false, null, or an element is returned from render
* still accepts arrays and iterables as host children
src/renderers/dom/shared/__tests__/CSSProperty-test.js
* should generate browser prefixes for its `isUnitlessNumber`
+6
View File
@@ -9,6 +9,12 @@ jest.mock('ReactDOMFeatureFlags', () => {
useFiber: flags.useFiber || !!process.env.REACT_DOM_JEST_USE_FIBER,
});
});
jest.mock('ReactFeatureFlags', () => {
const flags = require.requireActual('ReactFeatureFlags');
return Object.assign({}, flags, {
disableNewFiberFeatures: true,
});
});
// Error logging varies between Fiber and Stack;
// Rather than fork dozens of tests, mock the error-logging file by default.
+15
View File
@@ -18,6 +18,7 @@ import type { ReactNodeList } from 'ReactTypes';
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactControlledComponent = require('ReactControlledComponent');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactFeatureFlags = require('ReactFeatureFlags');
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
var ReactDOMFiberComponent = require('ReactDOMFiberComponent');
var ReactDOMFrameScheduling = require('ReactDOMFrameScheduling');
@@ -27,6 +28,8 @@ var ReactFiberReconciler = require('ReactFiberReconciler');
var ReactInputSelection = require('ReactInputSelection');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactPortal = require('ReactPortal');
var { isValidElement } = require('ReactElement');
var findDOMNode = require('findDOMNode');
var invariant = require('invariant');
@@ -49,6 +52,7 @@ if (__DEV__) {
var { updatedAncestorInfo } = validateDOMNesting;
}
const DOCUMENT_NODE = 9;
ReactDOMInjection.inject();
@@ -352,6 +356,17 @@ var ReactDOM = {
render(element : ReactElement<any>, container : DOMContainerElement, callback: ?Function) {
validateContainer(container);
if (ReactFeatureFlags.disableNewFiberFeatures) {
// Top-level check occurs here instead of inside child reconciler because
// because requirements vary between renderers. E.g. React Art
// allows arrays.
invariant(
isValidElement(element),
'render(): Invalid component element.'
);
}
return renderSubtreeIntoContainer(null, element, container, callback);
},
@@ -18,9 +18,17 @@ var ReactTestUtils = require('ReactTestUtils');
describe('ReactDOMFiber', () => {
var container;
var ReactFeatureFlags;
beforeEach(() => {
container = document.createElement('div');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
afterEach(() => {
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = true;
});
it('should render strings as children', () => {
@@ -1085,47 +1093,42 @@ describe('ReactDOMFiber', () => {
container
);
});
describe('disableNewFiberFeatures', () => {
var ReactFeatureFlags = require('ReactFeatureFlags');
beforeEach(() => {
ReactFeatureFlags.disableNewFiberFeatures = true;
});
afterEach(() => {
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('throws if non-element passed to top-level render', () => {
const message = 'render(): Invalid component element.';
expect(() => ReactDOM.render(null, container)).toThrow(message, container);
expect(() => ReactDOM.render(undefined, container)).toThrow(message, container);
expect(() => ReactDOM.render(false, container)).toThrow(message, container);
expect(() => ReactDOM.render('Hi', container)).toThrow(message, container);
expect(() => ReactDOM.render(999, container)).toThrow(message, container);
expect(() => ReactDOM.render([<div />], container)).toThrow(message, container);
});
it('throws if something other than false, null, or an element is returned from render', () => {
function Render(props) {
return props.children;
}
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/You may have returned undefined/);
});
it('still accepts arrays and iterables as host children', () => {
function Render(props) {
return <div>{props.children}</div>;
}
ReactDOM.render(<Render>{['foo', 'bar']}</Render>, container);
expect(container.textContent).toEqual('foobar');
ReactDOM.render(<Render>{new Set(['foo', 'bar'])}</Render>, container);
expect(container.textContent).toEqual('foobar');
});
});
}
});
// disableNewFiberFeatures currently defaults to true in test
describe('disableNewFiberFeatures', () => {
var container;
var ReactFeatureFlags;
beforeEach(() => {
container = document.createElement('div');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = true;
});
afterEach(() => {
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('throws if non-element passed to top-level render', () => {
const message = 'render(): Invalid component element.';
expect(() => ReactDOM.render(null, container)).toThrow(message, container);
expect(() => ReactDOM.render(undefined, container)).toThrow(message, container);
expect(() => ReactDOM.render(false, container)).toThrow(message, container);
expect(() => ReactDOM.render('Hi', container)).toThrow(message, container);
expect(() => ReactDOM.render(999, container)).toThrow(message, container);
expect(() => ReactDOM.render([<div />], container)).toThrow(message, container);
});
it('throws if something other than false, null, or an element is returned from render', () => {
function Render(props) {
return props.children;
}
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/You may have returned undefined/);
expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/You may have returned undefined/);
});
});
+31 -33
View File
@@ -75,7 +75,6 @@ const {
NoEffect,
Placement,
Deletion,
Err,
} = ReactTypeOfSideEffect;
function coerceRef(current: ?Fiber, element: ReactElement) {
@@ -1127,41 +1126,40 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
}
if (returnFiber.tag === HostRoot) {
// Top-level only accepts elements or portals
invariant(
// If the root has an error effect, this is an intentional unmount.
// Don't throw an error.
returnFiber.effectTag & Err,
'render(): Invalid component element.'
);
} else {
switch (returnFiber.tag) {
case ClassComponent: {
if (__DEV__) {
const instance = returnFiber.stateNode;
if (instance.render._isMockFunction) {
// We allow auto-mocks to proceed as if they're
// returning null.
break;
}
switch (returnFiber.tag) {
case ClassComponent: {
if (__DEV__) {
const instance = returnFiber.stateNode;
if (instance.render._isMockFunction) {
// We allow auto-mocks to proceed as if they're
// returning null.
break;
}
}
// Intentionally fall through to the next case, which handles both
// functions and classes
// eslint-disable-next-lined no-fallthrough
case FunctionalComponent: {
// Composites accept elements, portals, null, or false
const Component = returnFiber.type;
invariant(
newChild === null || newChild === false,
'%s.render(): A valid React element (or null) must be ' +
'returned. You may have returned undefined, an array or some ' +
'other invalid object.',
Component.displayName || Component.name || 'Component'
);
}
}
// Intentionally fall through to the next case, which handles both
// functions and classes
// eslint-disable-next-lined no-fallthrough
case FunctionalComponent: {
// Composites accept elements, portals, null, or false
const Component = returnFiber.type;
invariant(
newChild === null || newChild === false,
'%s(...): A valid React element (or null) must be ' +
'returned. You may have returned undefined, an array or some ' +
'other invalid object.',
Component.displayName || Component.name || 'Component'
);
}
}
if (typeof newChild === 'string' || typeof newChild === 'number') {
return placeSingleChild(reconcileSingleTextNode(
returnFiber,
currentFirstChild,
'' + newChild,
priority
));
}
if (isArray(newChild)) {
@@ -14,6 +14,7 @@
var React;
var ReactNoop;
var ReactCoroutine;
var ReactFeatureFlags;
describe('ReactCoroutine', () => {
beforeEach(() => {
@@ -21,6 +22,8 @@ describe('ReactCoroutine', () => {
React = require('React');
ReactNoop = require('ReactNoop');
ReactCoroutine = require('ReactCoroutine');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('should render a coroutine', () => {
@@ -13,12 +13,16 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncremental', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('should render a simple component', () => {
@@ -13,12 +13,15 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncrementalErrorHandling', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
function div(...children) {
@@ -13,12 +13,15 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncrementalReflection', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('handles isMounted even when the initial render is deferred', () => {
@@ -13,12 +13,15 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncrementalScheduling', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
function span(prop) {
@@ -13,12 +13,15 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncrementalSideEffects', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
function normalizeCodeLocInfo(str) {
@@ -13,12 +13,15 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
describe('ReactIncrementalUpdates', () => {
beforeEach(() => {
jest.resetModuleRegistry();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('applies updates in order of priority', () => {
@@ -13,6 +13,7 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
// This is a new feature in Fiber so I put it in its own test file. It could
// probably move to one of the other test files once it is official.
@@ -21,6 +22,8 @@ describe('ReactTopLevelFragment', function() {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('should render a simple fragment at the top of a component', function() {
@@ -13,6 +13,7 @@
var React;
var ReactNoop;
var ReactFeatureFlags;
// This is a new feature in Fiber so I put it in its own test file. It could
// probably move to one of the other test files once it is official.
@@ -21,6 +22,8 @@ describe('ReactTopLevelText', () => {
jest.resetModules();
React = require('React');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
it('should render a component returning strings directly from render', () => {
@@ -247,18 +247,24 @@ describe('ReactEmptyComponent', () => {
});
it('can render null at the top level', () => {
var ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
var div = document.createElement('div');
if (ReactDOMFeatureFlags.useFiber) {
ReactDOM.render(null, div);
expect(div.innerHTML).toBe('');
} else {
// Stack does not implement this.
expect(function() {
try {
if (ReactDOMFeatureFlags.useFiber) {
ReactDOM.render(null, div);
}).toThrowError(
'ReactDOM.render(): Invalid component element.'
);
expect(div.innerHTML).toBe('');
} else {
// Stack does not implement this.
expect(function() {
ReactDOM.render(null, div);
}).toThrowError(
'ReactDOM.render(): Invalid component element.'
);
}
} finally {
ReactFeatureFlags.disableNewFiberFeatures = true;
}
});
@@ -152,13 +152,8 @@ describe('ReactStatelessComponent', () => {
expect(function() {
ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
}).toThrowError(
ReactDOMFeatureFlags.useFiber ?
// Fiber gives a more specific error message for undefined because it
// supports more return types.
'NotAComponent(...): Nothing was returned from render' :
// Stack's message is generic.
'NotAComponent(...): A valid React element (or null) must be returned. ' +
'You may have returned undefined, an array or some other invalid object.'
'NotAComponent(...): A valid React element (or null) must be returned. ' +
'You may have returned undefined, an array or some other invalid object.'
);
});
@@ -14,8 +14,14 @@
var React = require('React');
var ReactTestRenderer = require('ReactTestRenderer');
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
var ReactFeatureFlags;
describe('ReactTestRenderer', () => {
beforeEach(() => {
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
});
function normalizeCodeLocInfo(str) {
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
}