From 18afb5731d2cd7d80c76430cb77b746e49425094 Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sat, 14 Jan 2017 20:43:53 +0000 Subject: [PATCH 1/7] Start work on shallow renderer Will need to remove the owner properly, this is just a proof-of-concept commit. Getting to know the codebase. --- scripts/fiber/tests-failing.txt | 12 ++ scripts/fiber/tests-passing.txt | 10 -- src/test/ReactShallowRenderer.js | 137 +------------------- src/test/ReactShallowRendererFiber.js | 124 +++++++++++++++++++ src/test/ReactShallowRendererStack.js | 144 ++++++++++++++++++++++ src/test/__tests__/ReactTestUtils-test.js | 2 +- 6 files changed, 286 insertions(+), 143 deletions(-) create mode 100644 src/test/ReactShallowRendererFiber.js create mode 100644 src/test/ReactShallowRendererStack.js diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index 884b8c3dc5eb5..badaba521b6e8 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -66,3 +66,15 @@ src/renderers/shared/shared/__tests__/ReactUpdates-test.js src/renderers/shared/shared/__tests__/refs-test.js * Should increase refs with an increase in divs + +src/test/__tests__/ReactTestUtils-test.js +* should throw for invalid elements +* should have shallow unmounting +* can shallow render with a ref +* lets you update shallowly rendered components +* can access the mounted component instance +* can shallowly render components with contextTypes +* can shallowly render components with ref as function +* can setState in componentWillMount when shallow rendering +* can pass context when shallowly rendering +* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index e1415a100ab38..3bc13c616f4f2 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1731,16 +1731,7 @@ src/shared/utils/__tests__/reactProdInvariant-test.js src/test/__tests__/ReactTestUtils-test.js * should have shallow rendering * should shallow render a functional component -* should throw for invalid elements -* should have shallow unmounting * can shallow render to null -* can shallow render with a ref -* lets you update shallowly rendered components -* can access the mounted component instance -* can shallowly render components with contextTypes -* can shallowly render components with ref as function -* can setState in componentWillMount when shallow rendering -* can pass context when shallowly rendering * can fail context when shallowly rendering * can scryRenderedDOMComponentsWithClass with TextComponent * can scryRenderedDOMComponentsWithClass with className contains \n @@ -1749,7 +1740,6 @@ src/test/__tests__/ReactTestUtils-test.js * should support injected wrapper components as DOM components * should change the value of an input field * should change the value of an input field in a component -* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering * should not warn when simulating events with extra properties * can scry with stateless components involved * should set the type of the event diff --git a/src/test/ReactShallowRenderer.js b/src/test/ReactShallowRenderer.js index ee50d9d6efc66..64f21ad0322e0 100644 --- a/src/test/ReactShallowRenderer.js +++ b/src/test/ReactShallowRenderer.js @@ -1,5 +1,5 @@ /** - * Copyright 2013-present, Facebook, Inc. + * Copyright (c) 2013-present Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -7,139 +7,12 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ReactShallowRenderer - * @preventMunge */ 'use strict'; -var React = require('React'); -var ReactDOMInjection = require('ReactDOMInjection'); -var ReactDOMStackInjection = require('ReactDOMStackInjection'); -var ReactCompositeComponent = require('ReactCompositeComponent'); -var ReactReconciler = require('ReactReconciler'); -var ReactUpdates = require('ReactUpdates'); +const ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); -var emptyObject = require('emptyObject'); -var getNextDebugID = require('getNextDebugID'); -var invariant = require('invariant'); - -class NoopInternalComponent { - constructor(element) { - this._renderedOutput = element; - this._currentElement = element; - - if (__DEV__) { - this._debugID = getNextDebugID(); - } - } - mountComponent() {} - receiveComponent(element) { - this._renderedOutput = element; - this._currentElement = element; - } - unmountComponent() {} - getHostNode() { - return undefined; - } - getPublicInstance() { - return null; - } -} - -var ShallowComponentWrapper = function(element) { - // TODO: Consolidate with instantiateReactComponent - if (__DEV__) { - this._debugID = getNextDebugID(); - } - - this.construct(element); -}; -Object.assign( - ShallowComponentWrapper.prototype, - ReactCompositeComponent, { - _constructComponent: - ReactCompositeComponent._constructComponentWithoutOwner, - _instantiateReactComponent: function(element) { - return new NoopInternalComponent(element); - }, - _replaceNodeWithMarkup: function() {}, - _renderValidatedComponent: - ReactCompositeComponent - ._renderValidatedComponentWithoutOwnerOrContext, - } -); - -function _batchedRender(renderer, element, context) { - var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true); - renderer._render(element, transaction, context); - ReactUpdates.ReactReconcileTransaction.release(transaction); -} - -class ReactShallowRenderer { - _instance = null; - getMountedInstance() { - return this._instance ? this._instance._instance : null; - } - render(element, context) { - // Ensure we've done the default injections. This might not be true in the - // case of a simple test that only requires React and the TestUtils in - // conjunction with an inline-requires transform. - ReactDOMInjection.inject(); - ReactDOMStackInjection.inject(); - - invariant( - React.isValidElement(element), - 'ReactShallowRenderer render(): Invalid component element.%s', - typeof element === 'function' ? - ' Instead of passing a component class, make sure to instantiate ' + - 'it by passing it to React.createElement.' : - '' - ); - invariant( - typeof element.type !== 'string', - 'ReactShallowRenderer render(): Shallow rendering works only with custom ' + - 'components, not primitives (%s). Instead of calling `.render(el)` and ' + - 'inspecting the rendered output, look at `el.props` directly instead.', - element.type - ); - - if (!context) { - context = emptyObject; - } - ReactUpdates.batchedUpdates(_batchedRender, this, element, context); - - return this.getRenderOutput(); - } - getRenderOutput() { - return ( - (this._instance && this._instance._renderedComponent && - this._instance._renderedComponent._renderedOutput) - || null - ); - } - unmount() { - if (this._instance) { - ReactReconciler.unmountComponent( - this._instance, - false, /* safely */ - false /* skipLifecycle */ - ); - } - } - _render(element, transaction, context) { - if (this._instance) { - ReactReconciler.receiveComponent( - this._instance, - element, - transaction, - context - ); - } else { - var instance = new ShallowComponentWrapper(element); - ReactReconciler.mountComponent(instance, transaction, null, null, context, 0); - this._instance = instance; - } - } -} - -module.exports = ReactShallowRenderer; +module.exports = ReactDOMFeatureFlags.useFiber + ? require('ReactShallowRendererFiber') + : require('ReactShallowRendererStack'); diff --git a/src/test/ReactShallowRendererFiber.js b/src/test/ReactShallowRendererFiber.js new file mode 100644 index 0000000000000..776c98d9c9559 --- /dev/null +++ b/src/test/ReactShallowRendererFiber.js @@ -0,0 +1,124 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactShallowRendererFiber + * @flow + */ + +'use strict'; + +const React = require('React'); +const emptyObject = require('emptyObject'); +const ReactFiberReconciler = require('ReactFiberReconciler'); + +type Props = { + children : Array, +}; + +type Container = {| + children : Array, + context : Object, +|}; + +type Instance = {| + type : string, + props : Props, + children : Array, + rootContainerInstance : Container, +|}; + +type TextInstance = {| + text : string, +|}; + +function removeOwner(element : React$Element) { + return { + ...element, + _owner: null, + } +} + +const reconciler = ReactFiberReconciler({ + getRootHostContext(rootContainerInstance : Container) { + return rootContainerInstance.context || emptyObject + }, + + getChildHostContext(parentHostContext, type) { + return parentHostContext; + }, + + createInstance(type : string, props : Props) : Instance { + return { + type, + props, + children: [], + }; + }, + + appendInitialChild(parentInstance, child) {}, + finalizeInitialChildren(parentInstance, type, props, rootContainerInstance) {}, + + prepareUpdate(instance, type, oldProps, newProps, hostContext) {}, + commitUpdate(instance, type, oldProps, newProps, rootContainerInstance, internalInstanceHandle) {}, + commitMount(instance, type, newProps, rootContainerInstance, internalInstanceHandle) {}, + + shouldSetTextContent(props) {}, + resetTextContent(instance) {}, + + createTextInstance(text : string) : TextInstance { + return { text } + }, + commitTextUpdate(textInstance, oldText, newText) {}, + + appendChild(parentInstance : Container | Instance, child : Instance) { + parentInstance.children.push({ + $$typeof: child.$$typeof, + type: child.type, + key: child.key, + _owner: null, + _store: {}, + ref: child.ref, + props: { + children: [...child.props.children].map(removeOwner), + }, + }); + }, + insertBefore(parentInstance, child, beforeChild) {}, + removeChild(parentInstance, child) {}, + + prepareForCommit() {}, + resetAfterCommit(commitInfo) {}, + + scheduleAnimationCallback: window.requestAnimaionFrame, + scheduleDeferredCallback: window.requestIdleCallback, + useSyncScheduling: true, +}); + +class ReactShallowRendererFiber { + container = (null: ?Container); + + render(element, context = emptyObject) { + this.container = { + context, + children: [], + }; + + const root = reconciler.createContainer(this.container); + + reconciler.updateContainer(element, root, null, null); + + return this.getRenderOutput(); + } + + getRenderOutput() { + const hasChildren = this.container.children.length > 0; + return hasChildren ? this.container.children[0] : null; + } +} + +module.exports = ReactShallowRendererFiber; diff --git a/src/test/ReactShallowRendererStack.js b/src/test/ReactShallowRendererStack.js new file mode 100644 index 0000000000000..6e86188e98936 --- /dev/null +++ b/src/test/ReactShallowRendererStack.js @@ -0,0 +1,144 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactShallowRendererStack + * @preventMunge + */ + +'use strict'; + +var React = require('React'); +var ReactDOMInjection = require('ReactDOMInjection'); +var ReactDOMStackInjection = require('ReactDOMStackInjection'); +var ReactCompositeComponent = require('ReactCompositeComponent'); +var ReactReconciler = require('ReactReconciler'); +var ReactUpdates = require('ReactUpdates'); + +var emptyObject = require('emptyObject'); +var getNextDebugID = require('getNextDebugID'); +var invariant = require('invariant'); + +class NoopInternalComponent { + constructor(element) { + this._renderedOutput = element; + this._currentElement = element; + + if (__DEV__) { + this._debugID = getNextDebugID(); + } + } + mountComponent() {} + receiveComponent(element) { + this._renderedOutput = element; + this._currentElement = element; + } + unmountComponent() {} + getHostNode() { + return undefined; + } + getPublicInstance() { + return null; + } +} + +var ShallowComponentWrapper = function(element) { + // TODO: Consolidate with instantiateReactComponent + if (__DEV__) { + this._debugID = getNextDebugID(); + } + + this.construct(element); +}; +Object.assign(ShallowComponentWrapper.prototype, ReactCompositeComponent, { + _constructComponent: ReactCompositeComponent._constructComponentWithoutOwner, + + _instantiateReactComponent(element) { + return new NoopInternalComponent(element); + }, + + _replaceNodeWithMarkup() {}, + + _renderValidatedComponent: ReactCompositeComponent + ._renderValidatedComponentWithoutOwnerOrContext, + } +); + +function _batchedRender(renderer, element, context) { + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true); + renderer._render(element, transaction, context); + ReactUpdates.ReactReconcileTransaction.release(transaction); +} + +class ReactShallowRendererStack { + _instance = null; + getMountedInstance() { + return this._instance ? this._instance._instance : null; + } + render(element, context) { + // Ensure we've done the default injections. This might not be true in the + // case of a simple test that only requires React and the TestUtils in + // conjunction with an inline-requires transform. + ReactDOMInjection.inject(); + ReactDOMStackInjection.inject(); + + invariant( + React.isValidElement(element), + 'ReactShallowRenderer render(): Invalid component element.%s', + typeof element === 'function' ? + ' Instead of passing a component class, make sure to instantiate ' + + 'it by passing it to React.createElement.' : + '' + ); + invariant( + typeof element.type !== 'string', + 'ReactShallowRenderer render(): Shallow rendering works only with custom ' + + 'components, not primitives (%s). Instead of calling `.render(el)` and ' + + 'inspecting the rendered output, look at `el.props` directly instead.', + element.type + ); + + if (!context) { + context = emptyObject; + } + ReactUpdates.batchedUpdates(_batchedRender, this, element, context); + + return this.getRenderOutput(); + } + getRenderOutput() { + return ( + (this._instance && this._instance._renderedComponent && + this._instance._renderedComponent._renderedOutput) + || null + ); + } + unmount() { + if (this._instance) { + ReactReconciler.unmountComponent( + this._instance, + false, /* safely */ + false /* skipLifecycle */ + ); + } + } + _render(element, transaction, context) { + if (this._instance) { + ReactReconciler.receiveComponent( + this._instance, + element, + transaction, + context + ); + } else { + var instance = new ShallowComponentWrapper(element); + ReactReconciler.mountComponent(instance, transaction, null, null, context, 0); + this._instance = instance; + } + } +} + +module.exports = ReactShallowRendererStack; diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js index d38caa49c96a3..345108333fe90 100644 --- a/src/test/__tests__/ReactTestUtils-test.js +++ b/src/test/__tests__/ReactTestUtils-test.js @@ -43,7 +43,7 @@ describe('ReactTestUtils', () => { expect(result.type).toBe('div'); expect(result.props.children).toEqual([ , - , + ]); }); From fe70f591e5912b19bfcbdab3107764566490f4ed Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 18:35:46 +0000 Subject: [PATCH 2/7] Add missing comma back --- src/test/__tests__/ReactTestUtils-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js index 345108333fe90..d38caa49c96a3 100644 --- a/src/test/__tests__/ReactTestUtils-test.js +++ b/src/test/__tests__/ReactTestUtils-test.js @@ -43,7 +43,7 @@ describe('ReactTestUtils', () => { expect(result.type).toBe('div'); expect(result.props.children).toEqual([ , - + , ]); }); From 693652807ad048d6080eac6ded4af00a416afd2c Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 19:40:41 +0000 Subject: [PATCH 3/7] createInstance should create a React$Element inst. ...without a __owner property. --- scripts/fiber/tests-failing.txt | 3 - scripts/fiber/tests-passing.txt | 3 + src/test/ReactShallowRendererFiber.js | 99 +++++++++++++++------------ 3 files changed, 58 insertions(+), 47 deletions(-) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index badaba521b6e8..e9f491b2c0196 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -70,11 +70,8 @@ src/renderers/shared/shared/__tests__/refs-test.js src/test/__tests__/ReactTestUtils-test.js * should throw for invalid elements * should have shallow unmounting -* can shallow render with a ref * lets you update shallowly rendered components * can access the mounted component instance -* can shallowly render components with contextTypes * can shallowly render components with ref as function * can setState in componentWillMount when shallow rendering * can pass context when shallowly rendering -* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 3bc13c616f4f2..861785161a02d 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1732,6 +1732,8 @@ src/test/__tests__/ReactTestUtils-test.js * should have shallow rendering * should shallow render a functional component * can shallow render to null +* can shallow render with a ref +* can shallowly render components with contextTypes * can fail context when shallowly rendering * can scryRenderedDOMComponentsWithClass with TextComponent * can scryRenderedDOMComponentsWithClass with className contains \n @@ -1740,6 +1742,7 @@ src/test/__tests__/ReactTestUtils-test.js * should support injected wrapper components as DOM components * should change the value of an input field * should change the value of an input field in a component +* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering * should not warn when simulating events with extra properties * can scry with stateless components involved * should set the type of the event diff --git a/src/test/ReactShallowRendererFiber.js b/src/test/ReactShallowRendererFiber.js index 776c98d9c9559..f781e01ef376c 100644 --- a/src/test/ReactShallowRendererFiber.js +++ b/src/test/ReactShallowRendererFiber.js @@ -12,81 +12,94 @@ 'use strict'; -const React = require('React'); const emptyObject = require('emptyObject'); const ReactFiberReconciler = require('ReactFiberReconciler'); +const ReactElementSymbol = require('ReactElementSymbol'); type Props = { children : Array, }; -type Container = {| - children : Array, +type Container = { + element : Instance | TextInstance | {}, context : Object, -|}; +}; type Instance = {| type : string, - props : Props, - children : Array, - rootContainerInstance : Container, + $$typeof : number, + props : Object, + ref : null, + key : null, + _store : Object, + _owner : null, |}; type TextInstance = {| text : string, |}; -function removeOwner(element : React$Element) { - return { - ...element, - _owner: null, - } -} - const reconciler = ReactFiberReconciler({ getRootHostContext(rootContainerInstance : Container) { - return rootContainerInstance.context || emptyObject + return rootContainerInstance.context || emptyObject; }, getChildHostContext(parentHostContext, type) { return parentHostContext; }, - createInstance(type : string, props : Props) : Instance { + getPublicInstance(instance) { + return instance; + }, + + createInstance(type : string, props : Props, hostContext, internalInstanceHandle) : Instance { + const { children, ...instanceProps } = props; + + if (children) { + instanceProps.children = []; + } + return { type, - props, - children: [], + $$typeof: ReactElementSymbol, + props: instanceProps, + key: null, + _owner: null, + _store: {}, + ref: null, }; }, - appendInitialChild(parentInstance, child) {}, - finalizeInitialChildren(parentInstance, type, props, rootContainerInstance) {}, + appendInitialChild(parentInstance, child) { + parentInstance.props.children.push(child); + }, + finalizeInitialChildren(parentInstance, type, props, rootContainerInstance) : boolean { + return false; + }, - prepareUpdate(instance, type, oldProps, newProps, hostContext) {}, + prepareUpdate(instance, type, oldProps, newProps, hostContext) : boolean { + return true; + }, commitUpdate(instance, type, oldProps, newProps, rootContainerInstance, internalInstanceHandle) {}, commitMount(instance, type, newProps, rootContainerInstance, internalInstanceHandle) {}, - shouldSetTextContent(props) {}, + shouldSetTextContent(props : Props) : boolean { + return ( + typeof props.children === 'string' || + typeof props.children === 'number' + ); + }, resetTextContent(instance) {}, createTextInstance(text : string) : TextInstance { - return { text } + return { text }; }, commitTextUpdate(textInstance, oldText, newText) {}, - appendChild(parentInstance : Container | Instance, child : Instance) { - parentInstance.children.push({ - $$typeof: child.$$typeof, - type: child.type, - key: child.key, - _owner: null, - _store: {}, - ref: child.ref, - props: { - children: [...child.props.children].map(removeOwner), - }, - }); + appendChild(parentInstance : Container | Instance, child : Instance | TextInstance) { + if (parentInstance.element) { + parentInstance.element = child; + } }, insertBefore(parentInstance, child, beforeChild) {}, removeChild(parentInstance, child) {}, @@ -100,24 +113,22 @@ const reconciler = ReactFiberReconciler({ }); class ReactShallowRendererFiber { - container = (null: ?Container); + container_ = (null: ?Container); - render(element, context = emptyObject) { - this.container = { + render(element : React$Element<*>, context = emptyObject) { + this.container_ = { context, - children: [], + element: emptyObject, }; - const root = reconciler.createContainer(this.container); - + const root = reconciler.createContainer(this.container_); reconciler.updateContainer(element, root, null, null); - return this.getRenderOutput(); } getRenderOutput() { - const hasChildren = this.container.children.length > 0; - return hasChildren ? this.container.children[0] : null; + const component = this.container_ && this.container_.element; + return component === emptyObject ? null : component; } } From c4df7b37f35d24a489bdfdf26412275952397621 Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 19:42:26 +0000 Subject: [PATCH 4/7] Lint --- src/test/ReactShallowRendererStack.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/test/ReactShallowRendererStack.js b/src/test/ReactShallowRendererStack.js index 6e86188e98936..81f787b33360d 100644 --- a/src/test/ReactShallowRendererStack.js +++ b/src/test/ReactShallowRendererStack.js @@ -54,17 +54,16 @@ var ShallowComponentWrapper = function(element) { this.construct(element); }; -Object.assign(ShallowComponentWrapper.prototype, ReactCompositeComponent, { - _constructComponent: ReactCompositeComponent._constructComponentWithoutOwner, - - _instantiateReactComponent(element) { - return new NoopInternalComponent(element); - }, - - _replaceNodeWithMarkup() {}, - - _renderValidatedComponent: ReactCompositeComponent - ._renderValidatedComponentWithoutOwnerOrContext, +Object.assign( + ShallowComponentWrapper.prototype, + ReactCompositeComponent, { + _constructComponent: ReactCompositeComponent._constructComponentWithoutOwner, + _instantiateReactComponent(element) { + return new NoopInternalComponent(element); + }, + _replaceNodeWithMarkup() {}, + _renderValidatedComponent: ReactCompositeComponent + ._renderValidatedComponentWithoutOwnerOrContext, } ); From fb3c445a5c9631953d72aae6f649ad2acb4acf92 Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 20:17:38 +0000 Subject: [PATCH 5/7] Should throw for invalid elements --- scripts/fiber/tests-failing.txt | 1 - scripts/fiber/tests-passing.txt | 1 + src/test/ReactShallowRendererFiber.js | 18 ++++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index e9f491b2c0196..f1865241d1aed 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -68,7 +68,6 @@ src/renderers/shared/shared/__tests__/refs-test.js * Should increase refs with an increase in divs src/test/__tests__/ReactTestUtils-test.js -* should throw for invalid elements * should have shallow unmounting * lets you update shallowly rendered components * can access the mounted component instance diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 861785161a02d..a40dcbb6b6928 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1731,6 +1731,7 @@ src/shared/utils/__tests__/reactProdInvariant-test.js src/test/__tests__/ReactTestUtils-test.js * should have shallow rendering * should shallow render a functional component +* should throw for invalid elements * can shallow render to null * can shallow render with a ref * can shallowly render components with contextTypes diff --git a/src/test/ReactShallowRendererFiber.js b/src/test/ReactShallowRendererFiber.js index f781e01ef376c..55eb93f16e50f 100644 --- a/src/test/ReactShallowRendererFiber.js +++ b/src/test/ReactShallowRendererFiber.js @@ -12,9 +12,11 @@ 'use strict'; +const React = require('React'); const emptyObject = require('emptyObject'); const ReactFiberReconciler = require('ReactFiberReconciler'); const ReactElementSymbol = require('ReactElementSymbol'); +const invariant = require('invariant'); type Props = { children : Array, @@ -116,6 +118,22 @@ class ReactShallowRendererFiber { container_ = (null: ?Container); render(element : React$Element<*>, context = emptyObject) { + invariant( + React.isValidElement(element), + 'ReactShallowRenderer render(): Invalid component element.%s', + typeof element === 'function' ? + ' Instead of passing a component class, make sure to instantiate ' + + 'it by passing it to React.createElement.' : + '' + ); + invariant( + typeof element.type !== 'string', + 'ReactShallowRenderer render(): Shallow rendering works only with custom ' + + 'components, not primitives (%s). Instead of calling `.render(el)` and ' + + 'inspecting the rendered output, look at `el.props` directly instead.', + element.type + ); + this.container_ = { context, element: emptyObject, From d540fc99854388000bbb570d7812d21f926bf62a Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 20:49:38 +0000 Subject: [PATCH 6/7] Add unmounting --- scripts/fiber/tests-failing.txt | 1 - scripts/fiber/tests-passing.txt | 1 + src/test/ReactShallowRendererFiber.js | 24 ++++++++++++++++-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index f1865241d1aed..a2c2c988585a5 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -68,7 +68,6 @@ src/renderers/shared/shared/__tests__/refs-test.js * Should increase refs with an increase in divs src/test/__tests__/ReactTestUtils-test.js -* should have shallow unmounting * lets you update shallowly rendered components * can access the mounted component instance * can shallowly render components with ref as function diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index a40dcbb6b6928..e19d1bb59d758 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1732,6 +1732,7 @@ src/test/__tests__/ReactTestUtils-test.js * should have shallow rendering * should shallow render a functional component * should throw for invalid elements +* should have shallow unmounting * can shallow render to null * can shallow render with a ref * can shallowly render components with contextTypes diff --git a/src/test/ReactShallowRendererFiber.js b/src/test/ReactShallowRendererFiber.js index 55eb93f16e50f..86521a15aca87 100644 --- a/src/test/ReactShallowRendererFiber.js +++ b/src/test/ReactShallowRendererFiber.js @@ -115,7 +115,7 @@ const reconciler = ReactFiberReconciler({ }); class ReactShallowRendererFiber { - container_ = (null: ?Container); + root_ = (null : ?Object) render(element : React$Element<*>, context = emptyObject) { invariant( @@ -133,20 +133,28 @@ class ReactShallowRendererFiber { 'inspecting the rendered output, look at `el.props` directly instead.', element.type ); - - this.container_ = { + + this.root_ = reconciler.createContainer({ context, element: emptyObject, - }; + }); - const root = reconciler.createContainer(this.container_); - reconciler.updateContainer(element, root, null, null); + reconciler.updateContainer(element, this.root_, null, null); return this.getRenderOutput(); } + unmount() { + if (this.root_ != null) { + reconciler.updateContainer(null, this.root_, null, () => { + this.root_ = null; + }); + } + } + getRenderOutput() { - const component = this.container_ && this.container_.element; - return component === emptyObject ? null : component; + return this.root_ != null + ? reconciler.findHostInstance(this.root_) + : null; } } From f690200ca7739dba2ff750cdcb008efe52ad7b49 Mon Sep 17 00:00:00 2001 From: Ragnar Valgeirsson Date: Sun, 22 Jan 2017 21:45:39 +0000 Subject: [PATCH 7/7] Render updates correctly --- scripts/fiber/tests-failing.txt | 2 -- scripts/fiber/tests-passing.txt | 2 ++ src/test/ReactShallowRendererFiber.js | 14 +++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt index a2c2c988585a5..0fa1de3ee5bee 100644 --- a/scripts/fiber/tests-failing.txt +++ b/scripts/fiber/tests-failing.txt @@ -68,8 +68,6 @@ src/renderers/shared/shared/__tests__/refs-test.js * Should increase refs with an increase in divs src/test/__tests__/ReactTestUtils-test.js -* lets you update shallowly rendered components * can access the mounted component instance -* can shallowly render components with ref as function * can setState in componentWillMount when shallow rendering * can pass context when shallowly rendering diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index e19d1bb59d758..4a89e34a63074 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1735,7 +1735,9 @@ src/test/__tests__/ReactTestUtils-test.js * should have shallow unmounting * can shallow render to null * can shallow render with a ref +* lets you update shallowly rendered components * can shallowly render components with contextTypes +* can shallowly render components with ref as function * can fail context when shallowly rendering * can scryRenderedDOMComponentsWithClass with TextComponent * can scryRenderedDOMComponentsWithClass with className contains \n diff --git a/src/test/ReactShallowRendererFiber.js b/src/test/ReactShallowRendererFiber.js index 86521a15aca87..41d610e0962e2 100644 --- a/src/test/ReactShallowRendererFiber.js +++ b/src/test/ReactShallowRendererFiber.js @@ -82,7 +82,9 @@ const reconciler = ReactFiberReconciler({ prepareUpdate(instance, type, oldProps, newProps, hostContext) : boolean { return true; }, - commitUpdate(instance, type, oldProps, newProps, rootContainerInstance, internalInstanceHandle) {}, + commitUpdate(instance, type, oldProps, newProps, rootContainerInstance, internalInstanceHandle) { + instance.props = newProps; + }, commitMount(instance, type, newProps, rootContainerInstance, internalInstanceHandle) {}, shouldSetTextContent(props : Props) : boolean { @@ -134,10 +136,12 @@ class ReactShallowRendererFiber { element.type ); - this.root_ = reconciler.createContainer({ - context, - element: emptyObject, - }); + if (this.root_ == null) { + this.root_ = reconciler.createContainer({ + context, + element: emptyObject, + }); + } reconciler.updateContainer(element, this.root_, null, null); return this.getRenderOutput();