From 70507560ac8c80330a35e5307a2ee8ba08a014ff Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sun, 24 Sep 2017 01:40:34 +0200 Subject: [PATCH] Remove Stack-only DEV code --- src/isomorphic/ReactEntry.js | 1 - .../hooks/ReactComponentTreeHook.js | 396 --- .../__tests__/ReactComponentTreeHook-test.js | 2146 ----------------- .../ReactHostOperationHistoryHook-test.js | 776 ------ src/renderers/__tests__/ReactPerf-test.js | 741 ------ .../dom/shared/DOMPropertyOperations.js | 27 - .../shared/hooks/ReactDOMInvalidARIAHook.js | 50 +- .../hooks/ReactDOMNullInputValuePropHook.js | 34 +- .../hooks/ReactDOMUnknownPropertyHook.js | 58 +- src/renderers/native/ReactNativeFiberEntry.js | 15 +- src/renderers/shared/ReactDebugTool.js | 439 ---- .../shared/ReactGlobalSharedState.js | 1 - src/renderers/shared/ReactInstrumentation.js | 21 - src/renderers/shared/ReactPerf.js | 456 ---- .../shared/__tests__/ReactDebugTool-test.js | 82 - src/test/ReactComponentTreeTestUtils.js | 105 - 16 files changed, 51 insertions(+), 5297 deletions(-) delete mode 100644 src/isomorphic/hooks/ReactComponentTreeHook.js delete mode 100644 src/renderers/__tests__/ReactComponentTreeHook-test.js delete mode 100644 src/renderers/__tests__/ReactHostOperationHistoryHook-test.js delete mode 100644 src/renderers/__tests__/ReactPerf-test.js delete mode 100644 src/renderers/shared/ReactDebugTool.js delete mode 100644 src/renderers/shared/ReactInstrumentation.js delete mode 100644 src/renderers/shared/ReactPerf.js delete mode 100644 src/renderers/shared/__tests__/ReactDebugTool-test.js delete mode 100644 src/test/ReactComponentTreeTestUtils.js diff --git a/src/isomorphic/ReactEntry.js b/src/isomorphic/ReactEntry.js index c5841fef96a..52415de1da4 100644 --- a/src/isomorphic/ReactEntry.js +++ b/src/isomorphic/ReactEntry.js @@ -58,7 +58,6 @@ var React = { if (__DEV__) { Object.assign(React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { // These should not be included in production. - ReactComponentTreeHook: require('ReactComponentTreeHook'), ReactDebugCurrentFrame: require('ReactDebugCurrentFrame'), }); } diff --git a/src/isomorphic/hooks/ReactComponentTreeHook.js b/src/isomorphic/hooks/ReactComponentTreeHook.js deleted file mode 100644 index 8f5105d32aa..00000000000 --- a/src/isomorphic/hooks/ReactComponentTreeHook.js +++ /dev/null @@ -1,396 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @providesModule ReactComponentTreeHook - */ - -'use strict'; - -var ReactCurrentOwner = require('ReactCurrentOwner'); -var invariant = require('fbjs/lib/invariant'); -var describeComponentFrame = require('describeComponentFrame'); - -if (__DEV__) { - var warning = require('fbjs/lib/warning'); -} - -import type {ReactElement, Source} from 'ReactElementType'; -import type {DebugID} from 'ReactInstanceType'; - -function isNative(fn) { - // Based on isNative() from Lodash - var funcToString = Function.prototype.toString; - var reIsNative = RegExp( - '^' + - funcToString - // Take an example native function source for comparison - .call(Object.prototype.hasOwnProperty) - // Strip regex characters so we can use it for regex - .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - // Remove hasOwnProperty from the template to make it generic - .replace( - /hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, - '$1.*?', - ) + - '$', - ); - try { - var source = funcToString.call(fn); - return reIsNative.test(source); - } catch (err) { - return false; - } -} - -var canUseCollections = - // Array.from - typeof Array.from === 'function' && - // Map - typeof Map === 'function' && - isNative(Map) && - // Map.prototype.keys - Map.prototype != null && - typeof Map.prototype.keys === 'function' && - isNative(Map.prototype.keys) && - // Set - typeof Set === 'function' && - isNative(Set) && - // Set.prototype.keys - Set.prototype != null && - typeof Set.prototype.keys === 'function' && - isNative(Set.prototype.keys); - -var setItem; -var getItem; -var removeItem; -var getItemIDs; -var addRoot; -var removeRoot; -var getRootIDs; - -if (canUseCollections) { - var itemMap = new Map(); - var rootIDSet = new Set(); - - setItem = function(id, item) { - itemMap.set(id, item); - }; - getItem = function(id) { - return itemMap.get(id); - }; - removeItem = function(id) { - itemMap.delete(id); - }; - getItemIDs = function() { - return Array.from(itemMap.keys()); - }; - - addRoot = function(id) { - rootIDSet.add(id); - }; - removeRoot = function(id) { - rootIDSet.delete(id); - }; - getRootIDs = function() { - return Array.from(rootIDSet.keys()); - }; -} else { - var itemByKey = {}; - var rootByKey = {}; - - // Use non-numeric keys to prevent V8 performance issues: - // https://github.com/facebook/react/pull/7232 - var getKeyFromID = function(id: DebugID): string { - return '.' + id; - }; - var getIDFromKey = function(key: string): DebugID { - return parseInt(key.substr(1), 10); - }; - - setItem = function(id, item) { - var key = getKeyFromID(id); - itemByKey[key] = item; - }; - getItem = function(id) { - var key = getKeyFromID(id); - return itemByKey[key]; - }; - removeItem = function(id) { - var key = getKeyFromID(id); - delete itemByKey[key]; - }; - getItemIDs = function() { - return Object.keys(itemByKey).map(getIDFromKey); - }; - - addRoot = function(id) { - var key = getKeyFromID(id); - rootByKey[key] = true; - }; - removeRoot = function(id) { - var key = getKeyFromID(id); - delete rootByKey[key]; - }; - getRootIDs = function() { - return Object.keys(rootByKey).map(getIDFromKey); - }; -} - -var unmountedIDs: Array = []; - -function purgeDeep(id) { - var item = getItem(id); - if (item) { - var {childIDs} = item; - removeItem(id); - childIDs.forEach(purgeDeep); - } -} - -function getDisplayName(element: ?ReactElement): string { - if (element == null) { - return '#empty'; - } else if (typeof element === 'string' || typeof element === 'number') { - return '#text'; - } else if (typeof element.type === 'string') { - return element.type; - } else { - return element.type.displayName || element.type.name || 'Unknown'; - } -} - -function describeID(id: DebugID): string { - const name = ReactComponentTreeHook.getDisplayName(id); - const element = ReactComponentTreeHook.getElement(id); - const ownerID = ReactComponentTreeHook.getOwnerID(id); - let ownerName; - - if (ownerID) { - ownerName = ReactComponentTreeHook.getDisplayName(ownerID); - } - warning( - element, - 'ReactComponentTreeHook: Missing React element for debugID %s when ' + - 'building stack', - id, - ); - return describeComponentFrame( - name || '', - element && element._source, - ownerName || '', - ); -} - -var ReactComponentTreeHook = { - onSetChildren(id: DebugID, nextChildIDs: Array): void { - var item = getItem(id); - invariant(item, 'Item must have been set'); - item.childIDs = nextChildIDs; - - for (var i = 0; i < nextChildIDs.length; i++) { - var nextChildID = nextChildIDs[i]; - var nextChild = getItem(nextChildID); - invariant( - nextChild, - 'Expected hook events to fire for the child ' + - 'before its parent includes it in onSetChildren().', - ); - invariant( - nextChild.childIDs != null || - typeof nextChild.element !== 'object' || - nextChild.element == null, - 'Expected onSetChildren() to fire for a container child ' + - 'before its parent includes it in onSetChildren().', - ); - invariant( - nextChild.isMounted, - 'Expected onMountComponent() to fire for the child ' + - 'before its parent includes it in onSetChildren().', - ); - if (nextChild.parentID == null) { - nextChild.parentID = id; - // TODO: This shouldn't be necessary but mounting a new root during in - // componentWillMount currently causes not-yet-mounted components to - // be purged from our tree data so their parent id is missing. - } - invariant( - nextChild.parentID === id, - 'Expected onBeforeMountComponent() parent and onSetChildren() to ' + - 'be consistent (%s has parents %s and %s).', - nextChildID, - nextChild.parentID, - id, - ); - } - }, - - onBeforeMountComponent( - id: DebugID, - element: ReactElement, - parentID: DebugID, - ): void { - var item = { - element, - parentID, - text: null, - childIDs: [], - isMounted: false, - updateCount: 0, - }; - setItem(id, item); - }, - - onBeforeUpdateComponent(id: DebugID, element: ReactElement): void { - var item = getItem(id); - if (!item || !item.isMounted) { - // We may end up here as a result of setState() in componentWillUnmount(). - // In this case, ignore the element. - return; - } - item.element = element; - }, - - onMountComponent(id: DebugID): void { - var item = getItem(id); - invariant(item, 'Item must have been set'); - item.isMounted = true; - var isRoot = item.parentID === 0; - if (isRoot) { - addRoot(id); - } - }, - - onUpdateComponent(id: DebugID): void { - var item = getItem(id); - if (!item || !item.isMounted) { - // We may end up here as a result of setState() in componentWillUnmount(). - // In this case, ignore the element. - return; - } - item.updateCount++; - }, - - onUnmountComponent(id: DebugID): void { - var item = getItem(id); - if (item) { - // We need to check if it exists. - // `item` might not exist if it is inside an error boundary, and a sibling - // error boundary child threw while mounting. Then this instance never - // got a chance to mount, but it still gets an unmounting event during - // the error boundary cleanup. - item.isMounted = false; - var isRoot = item.parentID === 0; - if (isRoot) { - removeRoot(id); - } - } - unmountedIDs.push(id); - }, - - purgeUnmountedComponents(): void { - if (ReactComponentTreeHook._preventPurging) { - // Should only be used for testing. - return; - } - - for (var i = 0; i < unmountedIDs.length; i++) { - var id = unmountedIDs[i]; - purgeDeep(id); - } - unmountedIDs.length = 0; - }, - - isMounted(id: DebugID): boolean { - var item = getItem(id); - return item ? item.isMounted : false; - }, - - getCurrentStackAddendum(): string { - var info = ''; - var currentOwner = ReactCurrentOwner.current; - if (currentOwner) { - invariant( - typeof currentOwner.tag !== 'number', - 'Fiber owners should not show up in Stack stack traces.', - ); - if (typeof currentOwner._debugID === 'number') { - info += ReactComponentTreeHook.getStackAddendumByID( - currentOwner._debugID, - ); - } - } - return info; - }, - - getStackAddendumByID(id: ?DebugID): string { - var info = ''; - while (id) { - info += describeID(id); - id = ReactComponentTreeHook.getParentID(id); - } - return info; - }, - - getChildIDs(id: DebugID): Array { - var item = getItem(id); - return item ? item.childIDs : []; - }, - - getDisplayName(id: DebugID): ?string { - var element = ReactComponentTreeHook.getElement(id); - if (!element) { - return null; - } - return getDisplayName(element); - }, - - getElement(id: DebugID): ?ReactElement { - var item = getItem(id); - return item ? item.element : null; - }, - - getOwnerID(id: DebugID): ?DebugID { - var element = ReactComponentTreeHook.getElement(id); - if (!element || !element._owner) { - return null; - } - return element._owner._debugID; - }, - - getParentID(id: DebugID): ?DebugID { - var item = getItem(id); - return item ? item.parentID : null; - }, - - getSource(id: DebugID): ?Source { - var item = getItem(id); - var element = item ? item.element : null; - var source = element != null ? element._source : null; - return source; - }, - - getText(id: DebugID): ?string { - var element = ReactComponentTreeHook.getElement(id); - if (typeof element === 'string') { - return element; - } else if (typeof element === 'number') { - return '' + element; - } else { - return null; - } - }, - - getUpdateCount(id: DebugID): number { - var item = getItem(id); - return item ? item.updateCount : 0; - }, - - getRootIDs, - getRegisteredIDs: getItemIDs, -}; - -module.exports = ReactComponentTreeHook; diff --git a/src/renderers/__tests__/ReactComponentTreeHook-test.js b/src/renderers/__tests__/ReactComponentTreeHook-test.js deleted file mode 100644 index 06b1fe07a7c..00000000000 --- a/src/renderers/__tests__/ReactComponentTreeHook-test.js +++ /dev/null @@ -1,2146 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -describe.skip('ReactComponentTreeHook', () => { - var React; - var ReactDOM; - var ReactInstanceMap; - var ReactComponentTreeHook; - var ReactDebugCurrentFiber; - var ReactComponentTreeTestUtils; - - beforeEach(() => { - jest.resetModules(); - - React = require('react'); - ReactDOM = require('react-dom'); - ReactInstanceMap = require('ReactInstanceMap'); - ReactDebugCurrentFiber = require('ReactDebugCurrentFiber'); - ReactComponentTreeHook = require('ReactComponentTreeHook'); - ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils'); - }); - - // This is the only part used both by Stack and Fiber. - describe('stack addenda', () => { - it('gets created', () => { - function getAddendum(element) { - var addendum = - ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || ''; - return addendum.replace(/\(at .+?:\d+\)/g, '(at **)'); - } - - function Anon() { - return null; - } - Object.defineProperty(Anon, 'name', { - value: null, - }); - // function Orange() { - // return null; - // } - - expectDev(getAddendum()).toBe(''); - // expectDev(getAddendum(
)).toBe('\n in div (at **)'); - // expectDev(getAddendum()).toBe('\n in Unknown (at **)'); - // expectDev(getAddendum()).toBe('\n in Orange (at **)'); - // expectDev(getAddendum(React.createElement(Orange))).toBe( - // '\n in Orange', - // ); - - var renders = 0; - //var rOwnedByQ; - - function Q() { - return /*rOwnedByQ =*/ React.createElement(R); - } - function R() { - return
; - } - class S extends React.Component { - componentDidMount() { - // Check that the parent path is still fetched when only S itself is on - // the stack. - this.forceUpdate(); - } - render() { - expectDev(getAddendum()).toBe( - '\n in S (at **)' + - '\n in div (at **)' + - '\n in R (created by Q)' + - '\n in Q (at **)', - ); - expectDev(getAddendum()).toBe( - // '\n in span (at **)' + - '\n in S (at **)' + - '\n in div (at **)' + - '\n in R (created by Q)' + - '\n in Q (at **)', - ); - expectDev(getAddendum(React.createElement('span'))).toBe( - // '\n in span (created by S)' + - '\n in S (at **)' + - '\n in div (at **)' + - '\n in R (created by Q)' + - '\n in Q (at **)', - ); - renders++; - return null; - } - } - ReactDOM.render(, document.createElement('div')); - expectDev(renders).toBe(2); - - // Make sure owner is fetched for the top element too. - // expectDev(getAddendum(rOwnedByQ)).toBe('\n in R (created by Q)'); - }); - }); - - // The rest of this file is not relevant for Fiber. - // TODO: remove tests below when we delete Stack. - - function assertTreeMatches(pairs) { - if (!Array.isArray(pairs[0])) { - pairs = [pairs]; - } - - var node = document.createElement('div'); - var currentElement; - var rootInstance; - - class Wrapper extends React.Component { - render() { - rootInstance = ReactInstanceMap.get(this); - return currentElement; - } - } - - function expectWrapperTreeToEqual(expectedTree, andStayMounted) { - ReactComponentTreeTestUtils.expectTree(rootInstance._debugID, { - displayName: 'Wrapper', - children: expectedTree ? [expectedTree] : [], - }); - var rootDisplayNames = ReactComponentTreeTestUtils.getRootDisplayNames(); - var registeredDisplayNames = ReactComponentTreeTestUtils.getRegisteredDisplayNames(); - if (!expectedTree) { - expectDev(rootDisplayNames).toEqual([]); - expectDev(registeredDisplayNames).toEqual([]); - } else if (andStayMounted) { - expectDev(rootDisplayNames).toContain('Wrapper'); - expectDev(registeredDisplayNames).toContain('Wrapper'); - } - } - - // Mount once, render updates, then unmount. - // Ensure the tree is correct on every step. - pairs.forEach(([element, expectedTree]) => { - currentElement = element; - - // Mount a new tree or update the existing tree. - ReactDOM.render(, node); - expectWrapperTreeToEqual(expectedTree, true); - - // Purging should have no effect - // on the tree we expect to see. - ReactComponentTreeHook.purgeUnmountedComponents(); - expectWrapperTreeToEqual(expectedTree, true); - }); - - // Unmounting the root node should purge - // the whole subtree automatically. - ReactDOM.unmountComponentAtNode(node); - expectWrapperTreeToEqual(null); - } - - describe('mount', () => { - it('uses displayName or Unknown for classic components', () => { - class Foo extends React.Component { - render() { - return null; - } - } - - Foo.displayName = 'Bar'; - - class Baz extends React.Component { - render() { - return null; - } - } - - class Qux extends React.Component { - render() { - return null; - } - } - - delete Qux.displayName; - - var element =
; - var tree = { - displayName: 'div', - children: [ - { - displayName: 'Bar', - children: [], - }, - { - displayName: 'Baz', - children: [], - }, - { - displayName: 'Unknown', - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('uses displayName, name, or ReactComponent for modern components', () => { - class Foo extends React.Component { - render() { - return null; - } - } - Foo.displayName = 'Bar'; - class Baz extends React.Component { - render() { - return null; - } - } - class Qux extends React.Component { - render() { - return null; - } - } - delete Qux.name; - - var element =
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: 'Bar', - children: [], - }, - { - displayName: 'Baz', - children: [], - }, - { - // Note: Ideally fallback name should be consistent (e.g. "Unknown") - displayName: 'ReactComponent', - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('uses displayName, name, or Object for factory components', () => { - function Foo() { - return { - render() { - return null; - }, - }; - } - Foo.displayName = 'Bar'; - function Baz() { - return { - render() { - return null; - }, - }; - } - function Qux() { - return { - render() { - return null; - }, - }; - } - delete Qux.name; - - var element =
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: 'Bar', - children: [], - }, - { - displayName: 'Baz', - children: [], - }, - { - displayName: 'Unknown', - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('uses displayName, name, or StatelessComponent for functional components', () => { - function Foo() { - return null; - } - Foo.displayName = 'Bar'; - function Baz() { - return null; - } - function Qux() { - return null; - } - delete Qux.name; - - var element =
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: 'Bar', - children: [], - }, - { - displayName: 'Baz', - children: [], - }, - { - displayName: 'Unknown', - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a host tree correctly', () => { - var element = ( -
-

- - Hi! - - Wow. -

-
-
- ); - var tree = { - displayName: 'div', - children: [ - { - displayName: 'p', - children: [ - { - displayName: 'span', - children: [ - { - displayName: '#text', - text: 'Hi!', - }, - ], - }, - { - displayName: '#text', - text: 'Wow.', - }, - ], - }, - { - displayName: 'hr', - element:
, - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a simple tree with composites correctly', () => { - class Foo extends React.Component { - render() { - return
; - } - } - - var element = ; - var tree = { - displayName: 'Foo', - element, - children: [ - { - displayName: 'div', - element:
, - children: [], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a tree with composites correctly', () => { - class Qux extends React.Component { - render() { - return null; - } - } - - function Foo() { - return { - render() { - return ; - }, - }; - } - function Bar({children}) { - return

{children}

; - } - class Baz extends React.Component { - render() { - return ( -
- - - Hi, - Mom - - Click me. -
- ); - } - } - - var element = ; - var tree = { - displayName: 'Baz', - element, - children: [ - { - displayName: 'div', - children: [ - { - displayName: 'Foo', - element: , - children: [ - { - displayName: 'Qux', - element: , - children: [], - }, - ], - }, - { - displayName: 'Bar', - children: [ - { - displayName: 'h1', - children: [ - { - displayName: 'span', - children: [ - { - displayName: '#text', - element: 'Hi,', - text: 'Hi,', - }, - ], - }, - { - displayName: '#text', - text: 'Mom', - element: 'Mom', - }, - ], - }, - ], - }, - { - displayName: 'a', - children: [ - { - displayName: '#text', - text: 'Click me.', - element: 'Click me.', - }, - ], - }, - ], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('ignores null children', () => { - class Foo extends React.Component { - render() { - return null; - } - } - var element = ; - var tree = { - displayName: 'Foo', - children: [], - }; - assertTreeMatches([element, tree]); - }); - - it('ignores false children', () => { - class Foo extends React.Component { - render() { - return false; - } - } - var element = ; - var tree = { - displayName: 'Foo', - children: [], - }; - assertTreeMatches([element, tree]); - }); - - it('reports text nodes as children', () => { - var element =
{'1'}{2}
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: '#text', - text: '1', - }, - { - displayName: '#text', - text: '2', - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a single text node as a child', () => { - var element =
{'1'}
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: '#text', - text: '1', - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a single number node as a child', () => { - var element =
{42}
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: '#text', - text: '42', - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports a zero as a child', () => { - var element =
{0}
; - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: '#text', - text: '0', - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('skips empty nodes for multiple children', () => { - function Foo() { - return
; - } - var element = ( -
- {'hi'} - {false} - {42} - {null} - -
- ); - var tree = { - displayName: 'div', - element, - children: [ - { - displayName: '#text', - text: 'hi', - element: 'hi', - }, - { - displayName: '#text', - text: '42', - element: 42, - }, - { - displayName: 'Foo', - element: , - children: [ - { - displayName: 'div', - element:
, - children: [], - }, - ], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('reports html content as no children', () => { - var element =
; - var tree = { - displayName: 'div', - children: [], - }; - assertTreeMatches([element, tree]); - }); - }); - - describe('update', () => { - describe('host component', () => { - it('updates text of a single text child', () => { - var elementBefore =
Hi.
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - var elementAfter =
Bye.
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from no children to a single text child', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
Hi.
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a single text child to no children', () => { - var elementBefore =
Hi.
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from html content to a single text child', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
Hi.
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a single text child to html content', () => { - var elementBefore =
Hi.
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from no children to multiple text children', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
{'Hi.'}{'Bye.'}
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from multiple text children to no children', () => { - var elementBefore =
{'Hi.'}{'Bye.'}
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from html content to multiple text children', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
{'Hi.'}{'Bye.'}
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from multiple text children to html content', () => { - var elementBefore =
{'Hi.'}{'Bye.'}
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from html content to no children', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from no children to html content', () => { - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from one text child to multiple text children', () => { - var elementBefore =
Hi.
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - - var elementAfter =
{'Hi.'}{'Bye.'}
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from multiple text children to one text child', () => { - var elementBefore =
{'Hi.'}{'Bye.'}
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - var elementAfter =
Hi.
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates text nodes when reordering', () => { - var elementBefore =
{'Hi.'}{'Bye.'}
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - { - displayName: '#text', - text: 'Bye.', - }, - ], - }; - - var elementAfter =
{'Bye.'}{'Hi.'}
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - { - displayName: '#text', - text: 'Hi.', - }, - ], - }; - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates host nodes when reordering with keys', () => { - var elementBefore = ( -
-
Hi.
-
Bye.
-
- ); - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }, - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - ], - }, - ], - }; - - var elementAfter = ( -
-
Bye.
-
Hi.
-
- ); - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - ], - }, - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates host nodes when reordering without keys', () => { - var elementBefore = ( -
-
Hi.
-
Bye.
-
- ); - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }, - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - ], - }, - ], - }; - - var elementAfter = ( -
-
Bye.
-
Hi.
-
- ); - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Bye.', - }, - ], - }, - { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates a single composite child of a different type', () => { - function Foo() { - return null; - } - - function Bar() { - return null; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [], - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates a single composite child of the same type', () => { - function Foo({children}) { - return children; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [ - { - displayName: 'span', - children: [], - }, - ], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from no children to a single composite child', () => { - function Foo() { - return null; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a single composite child to no children', () => { - function Foo() { - return null; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [], - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'div', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates mixed children', () => { - function Foo() { - return
; - } - var element1 = ( -
- {'hi'} - {false} - {42} - {null} - -
- ); - var tree1 = { - displayName: 'div', - children: [ - { - displayName: '#text', - text: 'hi', - }, - { - displayName: '#text', - text: '42', - }, - { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }, - ], - }; - - var element2 = ( -
- - {false} - {'hi'} - {null} -
- ); - var tree2 = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }, - { - displayName: '#text', - text: 'hi', - }, - ], - }; - - var element3 = ( -
- -
- ); - var tree3 = { - displayName: 'div', - children: [ - { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }, - ], - }; - - assertTreeMatches([ - [element1, tree1], - [element2, tree2], - [element3, tree3], - ]); - }); - }); - - describe('functional component', () => { - it('updates with a host child', () => { - function Foo({children}) { - return children; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'span', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from null to a host child', () => { - function Foo({children}) { - return children; - } - - var elementBefore = {null}; - var treeBefore = { - displayName: 'Foo', - children: [], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a host child to null', () => { - function Foo({children}) { - return children; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = {null}; - var treeAfter = { - displayName: 'Foo', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a host child to a composite child', () => { - function Bar() { - return null; - } - - function Foo({children}) { - return children; - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a composite child to a host child', () => { - function Bar() { - return null; - } - - function Foo({children}) { - return children; - } - - var elementBefore = ; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from null to a composite child', () => { - function Bar() { - return null; - } - - function Foo({children}) { - return children; - } - - var elementBefore = {null}; - var treeBefore = { - displayName: 'Foo', - children: [], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a composite child to null', () => { - function Bar() { - return null; - } - - function Foo({children}) { - return children; - } - - var elementBefore = ; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - var elementAfter = {null}; - var treeAfter = { - displayName: 'Foo', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - }); - - describe('class component', () => { - it('updates with a host child', () => { - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'span', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from null to a host child', () => { - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore = {null}; - var treeBefore = { - displayName: 'Foo', - children: [], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a host child to null', () => { - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = {null}; - var treeAfter = { - displayName: 'Foo', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a host child to a composite child', () => { - class Bar extends React.Component { - render() { - return null; - } - } - - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore =
; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a composite child to a host child', () => { - class Bar extends React.Component { - render() { - return null; - } - } - - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore = ; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - var elementAfter =
; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'div', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from null to a composite child', () => { - class Bar extends React.Component { - render() { - return null; - } - } - - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore = {null}; - var treeBefore = { - displayName: 'Foo', - children: [], - }; - - var elementAfter = ; - var treeAfter = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - - it('updates from a composite child to null', () => { - class Bar extends React.Component { - render() { - return null; - } - } - - class Foo extends React.Component { - render() { - return this.props.children; - } - } - - var elementBefore = ; - var treeBefore = { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - children: [], - }, - ], - }; - - var elementAfter = {null}; - var treeAfter = { - displayName: 'Foo', - children: [], - }; - - assertTreeMatches([ - [elementBefore, treeBefore], - [elementAfter, treeAfter], - ]); - }); - }); - }); - - describe('misc', () => { - it('tracks owner correctly', () => { - class Foo extends React.Component { - render() { - return

Hi.

; - } - } - function Bar({children}) { - return
{children} Mom
; - } - - // Note that owner is not calculated for text nodes - // because they are not created from real elements. - var element =
; - var tree = { - displayName: 'article', - children: [ - { - displayName: 'Foo', - children: [ - { - displayName: 'Bar', - ownerDisplayName: 'Foo', - children: [ - { - displayName: 'div', - ownerDisplayName: 'Bar', - children: [ - { - displayName: 'h1', - ownerDisplayName: 'Foo', - children: [ - { - displayName: '#text', - text: 'Hi.', - }, - ], - }, - { - displayName: '#text', - text: ' Mom', - }, - ], - }, - ], - }, - ], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - - it('purges unmounted components automatically', () => { - var node = document.createElement('div'); - var renderBar = true; - var fooInstance; - var barInstance; - - class Foo extends React.Component { - render() { - fooInstance = ReactInstanceMap.get(this); - return renderBar ? : null; - } - } - - class Bar extends React.Component { - render() { - barInstance = ReactInstanceMap.get(this); - return null; - } - } - - ReactDOM.render(, node); - ReactComponentTreeTestUtils.expectTree( - barInstance._debugID, - { - displayName: 'Bar', - parentDisplayName: 'Foo', - parentID: fooInstance._debugID, - children: [], - }, - 'Foo', - ); - - renderBar = false; - ReactDOM.render(, node); - ReactDOM.render(, node); - ReactComponentTreeTestUtils.expectTree( - barInstance._debugID, - { - displayName: 'Unknown', - children: [], - parentID: null, - }, - 'Foo', - ); - - ReactDOM.unmountComponentAtNode(node); - ReactComponentTreeTestUtils.expectTree( - barInstance._debugID, - { - displayName: 'Unknown', - children: [], - parentID: null, - }, - 'Foo', - ); - }); - - it('reports update counts', () => { - var node = document.createElement('div'); - - ReactDOM.render(
, node); - var divID = ReactComponentTreeHook.getRootIDs()[0]; - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0); - - ReactDOM.render(, node); - var spanID = ReactComponentTreeHook.getRootIDs()[0]; - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0); - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0); - - ReactDOM.render(, node); - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0); - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(1); - - ReactDOM.render(, node); - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0); - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(2); - - ReactDOM.unmountComponentAtNode(node); - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0); - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0); - }); - - it('does not report top-level wrapper as a root', () => { - var node = document.createElement('div'); - - ReactDOM.render(
, node); - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([ - 'div', - ]); - - ReactDOM.render(
, node); - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([ - 'div', - ]); - - ReactDOM.unmountComponentAtNode(node); - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([]); - expectDev( - ReactComponentTreeTestUtils.getRegisteredDisplayNames(), - ).toEqual([]); - }); - - it('registers inlined text nodes', () => { - var node = document.createElement('div'); - - ReactDOM.render(
hi
, node); - expectDev( - ReactComponentTreeTestUtils.getRegisteredDisplayNames(), - ).toEqual(['div', '#text']); - - ReactDOM.unmountComponentAtNode(node); - expectDev( - ReactComponentTreeTestUtils.getRegisteredDisplayNames(), - ).toEqual([]); - }); - }); - - describe('in environment without Map, Set and Array.from', () => { - var realMap; - var realSet; - var realArrayFrom; - - beforeEach(() => { - realMap = global.Map; - realSet = global.Set; - realArrayFrom = Array.from; - - global.Map = undefined; - global.Set = undefined; - Array.from = undefined; - - jest.resetModules(); - - React = require('react'); - ReactDOM = require('react-dom'); - ReactInstanceMap = require('ReactInstanceMap'); - ReactComponentTreeHook = require('ReactComponentTreeHook'); - ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils'); - }); - - afterEach(() => { - global.Map = realMap; - global.Set = realSet; - Array.from = realArrayFrom; - }); - - it('works', () => { - class Qux extends React.Component { - render() { - return null; - } - } - - function Foo() { - return { - render() { - return ; - }, - }; - } - function Bar({children}) { - return

{children}

; - } - class Baz extends React.Component { - render() { - return ( -
- - - Hi, - Mom - - Click me. -
- ); - } - } - - var element = ; - var tree = { - displayName: 'Baz', - element, - children: [ - { - displayName: 'div', - children: [ - { - displayName: 'Foo', - element: , - children: [ - { - displayName: 'Qux', - element: , - children: [], - }, - ], - }, - { - displayName: 'Bar', - children: [ - { - displayName: 'h1', - children: [ - { - displayName: 'span', - children: [ - { - displayName: '#text', - element: 'Hi,', - text: 'Hi,', - }, - ], - }, - { - displayName: '#text', - text: 'Mom', - element: 'Mom', - }, - ], - }, - ], - }, - { - displayName: 'a', - children: [ - { - displayName: '#text', - text: 'Click me.', - element: 'Click me.', - }, - ], - }, - ], - }, - ], - }; - assertTreeMatches([element, tree]); - }); - }); -}); diff --git a/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js b/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js deleted file mode 100644 index 891144b92a8..00000000000 --- a/src/renderers/__tests__/ReactHostOperationHistoryHook-test.js +++ /dev/null @@ -1,776 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -// This is only used by ReactPerf which is currently not supported on Fiber. -// Use browser timeline integration instead. -describe.skip('ReactHostOperationHistoryHook', () => { - var React; - var ReactPerf; - var ReactDOM; - var ReactDOMComponentTree; - var ReactHostOperationHistoryHook; - - beforeEach(() => { - jest.resetModules(); - - React = require('react'); - ReactPerf = require('ReactPerf'); - ReactDOM = require('react-dom'); - ReactDOMComponentTree = require('ReactDOMComponentTree'); - ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook'); - - ReactPerf.start(); - }); - - afterEach(() => { - ReactPerf.stop(); - }); - - function assertHistoryMatches(expectedHistory) { - var actualHistory = ReactHostOperationHistoryHook.getHistory(); - expectDev(actualHistory).toEqual(expectedHistory); - } - - describe('mount', () => { - it('gets recorded for host roots', () => { - var node = document.createElement('div'); - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(

Hi.

, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'mount', - payload: 'DIV', - }, - ]); - }); - - it('gets recorded for composite roots', () => { - function Foo() { - return

Hi.

; - } - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'mount', - payload: 'DIV', - }, - ]); - }); - - it('gets ignored for composite roots that return null', () => { - function Foo() { - return null; - } - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - // Empty DOM components should be invisible to hooks. - assertHistoryMatches([]); - }); - - it('gets recorded when a native is mounted deeply instead of null', () => { - var element; - function Foo() { - return element; - } - - ReactHostOperationHistoryHook._preventClearing = true; - - var node = document.createElement('div'); - element = null; - ReactDOM.render(, node); - - element = ; - ReactDOM.render(, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - // Since empty components should be invisible to hooks, - // we record a "mount" event rather than a "replace with". - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'mount', - payload: 'SPAN', - }, - ]); - }); - }); - - describe('update styles', () => { - it('gets recorded during mount', () => { - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render( -
, - node, - ); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update styles', - payload: { - color: 'red', - backgroundColor: 'yellow', - }, - }, - { - instanceID: inst._debugID, - type: 'mount', - payload: 'DIV', - }, - ]); - }); - - it('gets recorded during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - ReactDOM.render( -
, - node, - ); - ReactDOM.render(
, node); - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update styles', - payload: {color: 'red'}, - }, - { - instanceID: inst._debugID, - type: 'update styles', - payload: {color: 'blue', backgroundColor: 'yellow'}, - }, - { - instanceID: inst._debugID, - type: 'update styles', - payload: {color: '', backgroundColor: 'green'}, - }, - { - instanceID: inst._debugID, - type: 'update styles', - payload: {backgroundColor: ''}, - }, - ]); - }); - - it('gets ignored if the styles are shallowly equal', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render( -
, - node, - ); - ReactDOM.render( -
, - node, - ); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update styles', - payload: { - color: 'red', - backgroundColor: 'yellow', - }, - }, - ]); - }); - }); - - describe('update attribute', () => { - describe('simple attribute', () => { - it('gets recorded during mount', () => { - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 42}, - }, - { - instanceID: inst._debugID, - type: 'mount', - payload: 'DIV', - }, - ]); - }); - - it('gets recorded during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - ReactDOM.render(
, node); - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'mad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 42}, - }, - { - instanceID: inst._debugID, - type: 'remove attribute', - payload: 'className', - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 43}, - }, - ]); - }); - }); - - describe('attribute that gets removed with certain values', () => { - it('gets recorded as a removal during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {disabled: true}, - }, - { - instanceID: inst._debugID, - type: 'remove attribute', - payload: 'disabled', - }, - ]); - }); - }); - - describe('custom attribute', () => { - it('gets recorded during mount', () => { - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-x': 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-y': 42}, - }, - { - instanceID: inst._debugID, - type: 'mount', - payload: 'DIV', - }, - ]); - }); - - it('gets recorded during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - ReactDOM.render(
, node); - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-x': 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-x': 'mad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-y': 42}, - }, - { - instanceID: inst._debugID, - type: 'remove attribute', - payload: 'data-x', - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {'data-y': 43}, - }, - ]); - }); - }); - - describe('attribute on a web component', () => { - it('gets recorded during mount', () => { - var node = document.createElement('div'); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 42}, - }, - { - instanceID: inst._debugID, - type: 'mount', - payload: 'MY-COMPONENT', - }, - ]); - }); - - it('gets recorded during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - ReactDOM.render(, node); - ReactDOM.render(, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'rad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {className: 'mad'}, - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 42}, - }, - { - instanceID: inst._debugID, - type: 'remove attribute', - payload: 'className', - }, - { - instanceID: inst._debugID, - type: 'update attribute', - payload: {tabIndex: 43}, - }, - ]); - }); - }); - }); - - describe('replace text', () => { - describe('text content', () => { - it('gets recorded during an update from text content', () => { - var node = document.createElement('div'); - ReactDOM.render(
Hi.
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
Bye.
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace text', - payload: 'Bye.', - }, - ]); - }); - - it('gets recorded during an update from html', () => { - var node = document.createElement('div'); - ReactDOM.render( -
, - node, - ); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
Bye.
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace text', - payload: 'Bye.', - }, - ]); - }); - - it('gets recorded during an update from children', () => { - var node = document.createElement('div'); - ReactDOM.render(

, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
Bye.
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'remove child', - payload: {fromIndex: 0}, - }, - { - instanceID: inst._debugID, - type: 'remove child', - payload: {fromIndex: 1}, - }, - { - instanceID: inst._debugID, - type: 'replace text', - payload: 'Bye.', - }, - ]); - }); - - it('gets ignored if new text is equal', () => { - var node = document.createElement('div'); - ReactDOM.render(
Hi.
, node); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
Hi.
, node); - - assertHistoryMatches([]); - }); - }); - - describe('text node', () => { - it('gets recorded during an update', () => { - var node = document.createElement('div'); - ReactDOM.render(
{'Hi.'}{42}
, node); - var inst1 = ReactDOMComponentTree.getInstanceFromNode( - node.firstChild.childNodes[0], - ); - var inst2 = ReactDOMComponentTree.getInstanceFromNode( - node.firstChild.childNodes[3], - ); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
{'Bye.'}{43}
, node); - - assertHistoryMatches([ - { - instanceID: inst1._debugID, - type: 'replace text', - payload: 'Bye.', - }, - { - instanceID: inst2._debugID, - type: 'replace text', - payload: '43', - }, - ]); - }); - - it('gets ignored if new text is equal', () => { - var node = document.createElement('div'); - ReactDOM.render(
{'Hi.'}{42}
, node); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
{'Hi.'}{42}
, node); - - assertHistoryMatches([]); - }); - }); - }); - - describe('replace with', () => { - it('gets recorded when composite renders to a different type', () => { - var element; - function Foo() { - return element; - } - - var node = document.createElement('div'); - element =
; - ReactDOM.render(, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - element = ; - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace with', - payload: 'SPAN', - }, - ]); - }); - - it('gets recorded when composite renders to null after a native', () => { - var element; - function Foo() { - return element; - } - - var node = document.createElement('div'); - element = ; - ReactDOM.render(, node); - - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - element = null; - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace with', - payload: '#comment', - }, - ]); - }); - - it('gets ignored if the type has not changed', () => { - var element; - function Foo() { - return element; - } - - var node = document.createElement('div'); - element =
; - ReactDOM.render(, node); - - element =
; - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(, node); - - assertHistoryMatches([]); - }); - }); - - describe('replace children', () => { - it('gets recorded during an update from text content', () => { - var node = document.createElement('div'); - ReactDOM.render(
Hi.
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace children', - payload: 'Bye.', - }, - ]); - }); - - it('gets recorded during an update from html', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'replace children', - payload: 'Bye.', - }, - ]); - }); - - it('gets recorded during an update from children', () => { - var node = document.createElement('div'); - ReactDOM.render(

, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'remove child', - payload: {fromIndex: 0}, - }, - { - instanceID: inst._debugID, - type: 'remove child', - payload: {fromIndex: 1}, - }, - { - instanceID: inst._debugID, - type: 'replace children', - payload: 'Hi.', - }, - ]); - }); - - it('gets ignored if new html is equal', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - assertHistoryMatches([]); - }); - }); - - describe('insert child', () => { - it('gets reported when a child is inserted', () => { - var node = document.createElement('div'); - ReactDOM.render(
, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(

, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'insert child', - payload: {toIndex: 1, content: 'P'}, - }, - ]); - }); - }); - - describe('move child', () => { - it('gets reported when a child is inserted', () => { - var node = document.createElement('div'); - ReactDOM.render(

, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(

, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'move child', - payload: {fromIndex: 0, toIndex: 1}, - }, - ]); - }); - }); - - describe('remove child', () => { - it('gets reported when a child is removed', () => { - var node = document.createElement('div'); - ReactDOM.render(

, node); - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild); - - ReactHostOperationHistoryHook._preventClearing = true; - ReactDOM.render(
, node); - - assertHistoryMatches([ - { - instanceID: inst._debugID, - type: 'remove child', - payload: {fromIndex: 1}, - }, - ]); - }); - }); -}); diff --git a/src/renderers/__tests__/ReactPerf-test.js b/src/renderers/__tests__/ReactPerf-test.js deleted file mode 100644 index b09519a1982..00000000000 --- a/src/renderers/__tests__/ReactPerf-test.js +++ /dev/null @@ -1,741 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -// ReactPerf is currently not supported on Fiber. -// Use browser timeline integration instead. -describe.skip('ReactPerf', () => { - var React; - var ReactDOM; - var ReactPerf; - var ReactTestUtils; - var emptyFunction; - - var App; - var Box; - var Div; - var LifeCycle; - - beforeEach(() => { - var now = 0; - jest.setMock('fbjs/lib/performanceNow', function() { - return now++; - }); - - if (typeof console.table !== 'function') { - console.table = () => {}; - console.table.isFake = true; - } - - React = require('react'); - ReactDOM = require('react-dom'); - ReactPerf = require('ReactPerf'); - ReactTestUtils = require('react-dom/test-utils'); - emptyFunction = require('fbjs/lib/emptyFunction'); - - App = class extends React.Component { - render() { - return
; - } - }; - - Box = class extends React.Component { - render() { - return
; - } - }; - - // ReactPerf only measures composites, so we put everything in one. - Div = class extends React.Component { - render() { - return
; - } - }; - - LifeCycle = class extends React.Component { - shouldComponentUpdate = emptyFunction.thatReturnsTrue; - componentWillMount = emptyFunction; - componentDidMount = emptyFunction; - componentWillReceiveProps = emptyFunction; - componentWillUpdate = emptyFunction; - componentDidUpdate = emptyFunction; - componentWillUnmount = emptyFunction; - render = emptyFunction.thatReturnsNull; - }; - }); - - afterEach(() => { - if (console.table.isFake) { - delete console.table; - } - }); - - function measure(fn) { - ReactPerf.start(); - fn(); - ReactPerf.stop(); - - // Make sure none of the methods crash. - ReactPerf.getWasted(); - ReactPerf.getInclusive(); - ReactPerf.getExclusive(); - ReactPerf.getOperations(); - - return ReactPerf.getLastMeasurements(); - } - - it('should count no-op update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(, container); - var measurements = measure(() => { - ReactDOM.render(, container); - }); - - var summary = ReactPerf.getWasted(measurements); - expect(summary).toEqual([ - { - key: 'App', - instanceCount: 1, - inclusiveRenderDuration: 3, - renderCount: 1, - }, - { - key: 'App > Box', - instanceCount: 2, - inclusiveRenderDuration: 2, - renderCount: 2, - }, - ]); - }); - - it('should count no-op update in child as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(, container); - - // Here, we add a Box -- two of the updates are wasted time (but the - // addition of the third is not) - var measurements = measure(() => { - ReactDOM.render(, container); - }); - - var summary = ReactPerf.getWasted(measurements); - expect(summary).toEqual([ - { - key: 'App > Box', - instanceCount: 1, - inclusiveRenderDuration: 1, - renderCount: 1, - }, - ]); - }); - - function expectNoWaste(fn) { - var measurements = measure(fn); - var summary = ReactPerf.getWasted(measurements); - expect(summary).toEqual([]); - } - - it('should not count initial render as waste', () => { - expectNoWaste(() => { - ReactTestUtils.renderIntoDocument(); - }); - }); - - it('should not count unmount as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
hello
, container); - expectNoWaste(() => { - ReactDOM.unmountComponentAtNode(container); - }); - }); - - it('should not count content update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
hello
, container); - expectNoWaste(() => { - ReactDOM.render(
hello world
, container); - }); - }); - - it('should not count child addition as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
, container); - expectNoWaste(() => { - ReactDOM.render(
, container); - }); - }); - - it('should not count child removal as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
, container); - expectNoWaste(() => { - ReactDOM.render(
, container); - }); - }); - - it('should not count property update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
hey
, container); - expectNoWaste(() => { - ReactDOM.render(
hey
, container); - }); - }); - - it('should not count style update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
hey
, container); - expectNoWaste(() => { - ReactDOM.render(
hey
, container); - }); - }); - - it('should not count property removal as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
hey
, container); - expectNoWaste(() => { - ReactDOM.render(
hey
, container); - }); - }); - - it('should not count raw HTML update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render( -
, - container, - ); - expectNoWaste(() => { - ReactDOM.render( -
, - container, - ); - }); - }); - - it('should not count child reordering as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
, container); - expectNoWaste(() => { - ReactDOM.render(
, container); - }); - }); - - it('should not count text update as waste', () => { - var container = document.createElement('div'); - ReactDOM.render(
{'hello'}{'world'}
, container); - expectNoWaste(() => { - ReactDOM.render(
{'hello'}{'friend'}
, container); - }); - }); - - it('should not count replacing null with a host as waste', () => { - var element = null; - function Foo() { - return element; - } - var container = document.createElement('div'); - ReactDOM.render(, container); - expectNoWaste(() => { - element =
; - ReactDOM.render(, container); - }); - }); - - it('should not count replacing a host with null as waste', () => { - var element =
; - function Foo() { - return element; - } - var container = document.createElement('div'); - ReactDOM.render(, container); - expectNoWaste(() => { - element = null; - ReactDOM.render(, container); - }); - }); - - it('should include stats for components unmounted during measurement', () => { - var container = document.createElement('div'); - var measurements = measure(() => { - ReactDOM.render(
, container); - ReactDOM.render(
, container); - }); - expect(ReactPerf.getExclusive(measurements)).toEqual([ - { - key: 'Div', - instanceCount: 3, - counts: {ctor: 3, render: 4}, - durations: {ctor: 3, render: 4}, - totalDuration: 7, - }, - ]); - }); - - it('should include lifecycle methods in measurements', () => { - var container = document.createElement('div'); - var measurements = measure(() => { - var instance = ReactDOM.render(, container); - ReactDOM.render(, container); - instance.setState({}); - ReactDOM.unmountComponentAtNode(container); - }); - expect(ReactPerf.getExclusive(measurements)).toEqual([ - { - key: 'LifeCycle', - instanceCount: 1, - totalDuration: 14, - counts: { - ctor: 1, - shouldComponentUpdate: 2, - componentWillMount: 1, - componentDidMount: 1, - componentWillReceiveProps: 1, - componentWillUpdate: 2, - componentDidUpdate: 2, - componentWillUnmount: 1, - render: 3, - }, - durations: { - ctor: 1, - shouldComponentUpdate: 2, - componentWillMount: 1, - componentDidMount: 1, - componentWillReceiveProps: 1, - componentWillUpdate: 2, - componentDidUpdate: 2, - componentWillUnmount: 1, - render: 3, - }, - }, - ]); - }); - - it('should include render time of functional components', () => { - function Foo() { - return null; - } - - var container = document.createElement('div'); - var measurements = measure(() => { - ReactDOM.render(, container); - }); - expect(ReactPerf.getExclusive(measurements)).toEqual([ - { - key: 'Foo', - instanceCount: 1, - totalDuration: 1, - counts: { - render: 1, - }, - durations: { - render: 1, - }, - }, - ]); - }); - - it('should not count time in a portal towards lifecycle method', () => { - function Foo() { - return null; - } - - var portalContainer = document.createElement('div'); - class Portal extends React.Component { - componentDidMount() { - ReactDOM.render(, portalContainer); - } - render() { - return null; - } - } - - var container = document.createElement('div'); - var measurements = measure(() => { - ReactDOM.render(, container); - }); - - expect(ReactPerf.getExclusive(measurements)).toEqual([ - { - key: 'Portal', - instanceCount: 1, - totalDuration: 6, - counts: { - ctor: 1, - componentDidMount: 1, - render: 1, - }, - durations: { - ctor: 1, - // We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time. - // Otherwise it would artificially float to the top even though its exclusive time is small. - // This is how we get 4 as a number with the performanceNow() mock: - // - we capture the time we enter componentDidMount (n = 0) - // - we capture the time when we enter a nested flush (n = 1) - // - in the nested flush, we call it twice: before and after rendering. (n = 3) - // - we capture the time when we exit a nested flush (n = 4) - // - we capture the time we exit componentDidMount (n = 5) - // Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4. - componentDidMount: 4, - render: 1, - }, - }, - { - key: 'Foo', - instanceCount: 1, - totalDuration: 1, - counts: { - render: 1, - }, - durations: { - render: 1, - }, - }, - ]); - }); - - it('warns once when using getMeasurementsSummaryMap', () => { - var measurements = measure(() => {}); - spyOn(console, 'warn'); - ReactPerf.getMeasurementsSummaryMap(measurements); - expectDev(console.warn.calls.count()).toBe(1); - expectDev(console.warn.calls.argsFor(0)[0]).toContain( - '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' + - '`ReactPerf.getWasted(...)` instead.', - ); - - ReactPerf.getMeasurementsSummaryMap(measurements); - expectDev(console.warn.calls.count()).toBe(1); - }); - - it('warns once when using printDOM', () => { - var measurements = measure(() => {}); - spyOn(console, 'warn'); - ReactPerf.printDOM(measurements); - expectDev(console.warn.calls.count()).toBe(1); - expectDev(console.warn.calls.argsFor(0)[0]).toContain( - '`ReactPerf.printDOM(...)` is deprecated. Use ' + - '`ReactPerf.printOperations(...)` instead.', - ); - - ReactPerf.printDOM(measurements); - expectDev(console.warn.calls.count()).toBe(1); - }); - - it('returns isRunning state', () => { - expect(ReactPerf.isRunning()).toBe(false); - - ReactPerf.start(); - expect(ReactPerf.isRunning()).toBe(true); - - ReactPerf.stop(); - expect(ReactPerf.isRunning()).toBe(false); - }); - - it('start has no effect when already running', () => { - expect(ReactPerf.isRunning()).toBe(false); - - ReactPerf.start(); - expect(ReactPerf.isRunning()).toBe(true); - - ReactPerf.start(); - expect(ReactPerf.isRunning()).toBe(true); - - ReactPerf.stop(); - expect(ReactPerf.isRunning()).toBe(false); - }); - - it('stop has no effect when already stopped', () => { - expect(ReactPerf.isRunning()).toBe(false); - - ReactPerf.stop(); - expect(ReactPerf.isRunning()).toBe(false); - - ReactPerf.stop(); - expect(ReactPerf.isRunning()).toBe(false); - }); - - it('should print console error only once', () => { - __DEV__ = false; - - spyOn(console, 'error'); - - expect(ReactPerf.getLastMeasurements()).toEqual([]); - expect(ReactPerf.getExclusive()).toEqual([]); - expect(ReactPerf.getInclusive()).toEqual([]); - expect(ReactPerf.getWasted()).toEqual([]); - expect(ReactPerf.getOperations()).toEqual([]); - expect(ReactPerf.printExclusive()).toEqual(undefined); - expect(ReactPerf.printInclusive()).toEqual(undefined); - expect(ReactPerf.printWasted()).toEqual(undefined); - expect(ReactPerf.printOperations()).toEqual(undefined); - expect(ReactPerf.start()).toBe(undefined); - expect(ReactPerf.stop()).toBe(undefined); - expect(ReactPerf.isRunning()).toBe(false); - - expectDev(console.error.calls.count()).toBe(1); - - __DEV__ = true; - }); - - it('should work when measurement starts during reconciliation', () => { - // https://github.com/facebook/react/issues/6949#issuecomment-230371009 - class Measurer extends React.Component { - componentWillMount() { - ReactPerf.start(); - } - - componentDidMount() { - ReactPerf.stop(); - } - - componentWillUpdate() { - ReactPerf.start(); - } - - componentDidUpdate() { - ReactPerf.stop(); - } - - render() { - // Force reconciliation despite constant element - return React.cloneElement(this.props.children); - } - } - - var container = document.createElement('div'); - ReactDOM.render(, container); - expect(ReactPerf.getWasted()).toEqual([]); - - ReactDOM.render(, container); - expect(ReactPerf.getWasted()).toEqual([ - { - key: 'Measurer', - instanceCount: 1, - inclusiveRenderDuration: 4, - renderCount: 1, - }, - { - key: 'App', - instanceCount: 1, - inclusiveRenderDuration: 3, - renderCount: 1, - }, - { - key: 'App > Box', - instanceCount: 2, - inclusiveRenderDuration: 2, - renderCount: 2, - }, - ]); - }); - - it('should not print errant warnings if render() throws', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - render() { - throw thrownErr; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactPerf.stop(); - }); - - it('should not print errant warnings if componentWillMount() throws', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - componentWillMount() { - throw thrownErr; - } - render() { - return
; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactPerf.stop(); - }); - - it('should not print errant warnings if componentDidMount() throws', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - componentDidMount() { - throw thrownErr; - } - render() { - return
; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactPerf.stop(); - }); - - it('should not print errant warnings if portal throws in render()', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - render() { - throw thrownErr; - } - } - class EvilPortal extends React.Component { - componentDidMount() { - var portalContainer = document.createElement('div'); - ReactDOM.render(, portalContainer); - } - render() { - return
; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactDOM.unmountComponentAtNode(container); - ReactPerf.stop(); - }); - - it('should not print errant warnings if portal throws in componentWillMount()', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - componentWillMount() { - throw thrownErr; - } - render() { - return
; - } - } - class EvilPortal extends React.Component { - componentWillMount() { - var portalContainer = document.createElement('div'); - ReactDOM.render(, portalContainer); - } - render() { - return
; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactDOM.unmountComponentAtNode(container); - ReactPerf.stop(); - }); - - it('should not print errant warnings if portal throws in componentDidMount()', () => { - var container = document.createElement('div'); - var thrownErr = new Error('Muhaha!'); - - class Evil extends React.Component { - componentDidMount() { - throw thrownErr; - } - render() { - return
; - } - } - class EvilPortal extends React.Component { - componentDidMount() { - var portalContainer = document.createElement('div'); - ReactDOM.render(, portalContainer); - } - render() { - return
; - } - } - - ReactPerf.start(); - try { - ReactDOM.render( -
- - -
, - container, - ); - } catch (err) { - if (err !== thrownErr) { - throw err; - } - } - ReactDOM.unmountComponentAtNode(container); - ReactPerf.stop(); - }); -}); diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js index d358966b399..0c278cfdc80 100644 --- a/src/renderers/dom/shared/DOMPropertyOperations.js +++ b/src/renderers/dom/shared/DOMPropertyOperations.js @@ -10,8 +10,6 @@ 'use strict'; var DOMProperty = require('DOMProperty'); -var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactInstrumentation = require('ReactInstrumentation'); if (__DEV__) { var warning = require('fbjs/lib/warning'); @@ -201,11 +199,6 @@ var DOMPropertyOperations = { if (__DEV__) { var payload = {}; payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID, - type: 'update attribute', - payload: payload, - }); } }, @@ -222,11 +215,6 @@ var DOMPropertyOperations = { if (__DEV__) { var payload = {}; payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID, - type: 'update attribute', - payload: payload, - }); } }, @@ -238,13 +226,6 @@ var DOMPropertyOperations = { */ deleteValueForAttribute: function(node, name) { node.removeAttribute(name); - if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID, - type: 'remove attribute', - payload: name, - }); - } }, /** @@ -272,14 +253,6 @@ var DOMPropertyOperations = { } else { node.removeAttribute(name); } - - if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation({ - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID, - type: 'remove attribute', - payload: name, - }); - } }, }; diff --git a/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js index fe64179419b..d54d0e78788 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js @@ -22,27 +22,17 @@ var hasOwnProperty = Object.prototype.hasOwnProperty; if (__DEV__) { var warning = require('fbjs/lib/warning'); - var { - ReactComponentTreeHook, - ReactDebugCurrentFrame, - } = require('ReactGlobalSharedState'); - var {getStackAddendumByID} = ReactComponentTreeHook; + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); var validAriaProperties = require('./validAriaProperties'); } -function getStackAddendum(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame.getStackAddendum(); - return stack != null ? stack : ''; - } +function getStackAddendum() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; } -function validateProperty(tagName, name, debugID) { +function validateProperty(tagName, name) { if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { return true; } @@ -60,7 +50,7 @@ function validateProperty(tagName, name, debugID) { false, 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.%s', name, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -72,7 +62,7 @@ function validateProperty(tagName, name, debugID) { 'Invalid ARIA attribute `%s`. Did you mean `%s`?%s', name, correctName, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -98,7 +88,7 @@ function validateProperty(tagName, name, debugID) { 'Unknown ARIA attribute `%s`. Did you mean `%s`?%s', name, standardName, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -108,11 +98,11 @@ function validateProperty(tagName, name, debugID) { return true; } -function warnInvalidARIAProps(type, props, debugID) { +function warnInvalidARIAProps(type, props) { const invalidProps = []; for (var key in props) { - var isValid = validateProperty(type, key, debugID); + var isValid = validateProperty(type, key); if (!isValid) { invalidProps.push(key); } @@ -129,7 +119,7 @@ function warnInvalidARIAProps(type, props, debugID) { 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, - getStackAddendum(debugID), + getStackAddendum(), ); } else if (invalidProps.length > 1) { warning( @@ -138,32 +128,20 @@ function warnInvalidARIAProps(type, props, debugID) { 'For details, see https://fb.me/invalid-aria-prop%s', unknownPropString, type, - getStackAddendum(debugID), + getStackAddendum(), ); } } -function validateProperties(type, props, debugID /* Stack only */) { +function validateProperties(type, props) { if (isCustomComponent(type, props)) { return; } - warnInvalidARIAProps(type, props, debugID); + warnInvalidARIAProps(type, props); } var ReactDOMInvalidARIAHook = { - // Fiber validateProperties, - // Stack - onBeforeMountComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, - onBeforeUpdateComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, }; module.exports = ReactDOMInvalidARIAHook; diff --git a/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js index 5be6292c16b..74ddf2b8889 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js @@ -11,27 +11,17 @@ if (__DEV__) { var warning = require('fbjs/lib/warning'); - var { - ReactComponentTreeHook, - ReactDebugCurrentFrame, - } = require('ReactGlobalSharedState'); - var {getStackAddendumByID} = ReactComponentTreeHook; + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); } var didWarnValueNull = false; -function getStackAddendum(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame.getStackAddendum(); - return stack != null ? stack : ''; - } +function getStackAddendum() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; } -function validateProperties(type, props, debugID /* Stack only */) { +function validateProperties(type, props) { if (type !== 'input' && type !== 'textarea' && type !== 'select') { return; } @@ -42,7 +32,7 @@ function validateProperties(type, props, debugID /* Stack only */) { 'Consider using the empty string to clear the component or `undefined` ' + 'for uncontrolled components.%s', type, - getStackAddendum(debugID), + getStackAddendum(), ); didWarnValueNull = true; @@ -50,19 +40,7 @@ function validateProperties(type, props, debugID /* Stack only */) { } var ReactDOMNullInputValuePropHook = { - // Fiber validateProperties, - // Stack - onBeforeMountComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, - onBeforeUpdateComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, }; module.exports = ReactDOMNullInputValuePropHook; diff --git a/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js index 01b254f723b..75d20e7d776 100644 --- a/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js +++ b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js @@ -15,22 +15,12 @@ var isCustomComponent = require('isCustomComponent'); if (__DEV__) { var warning = require('fbjs/lib/warning'); - var { - ReactComponentTreeHook, - ReactDebugCurrentFrame, - } = require('ReactGlobalSharedState'); - var {getStackAddendumByID} = ReactComponentTreeHook; + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState'); } -function getStackAddendum(debugID) { - if (debugID != null) { - // This can only happen on Stack - return getStackAddendumByID(debugID); - } else { - // This can only happen on Fiber / Server - var stack = ReactDebugCurrentFrame.getStackAddendum(); - return stack != null ? stack : ''; - } +function getStackAddendum() { + var stack = ReactDebugCurrentFrame.getStackAddendum(); + return stack != null ? stack : ''; } if (__DEV__) { @@ -43,7 +33,7 @@ if (__DEV__) { ); var possibleStandardNames = require('possibleStandardNames'); - var validateProperty = function(tagName, name, value, debugID) { + var validateProperty = function(tagName, name, value) { if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { return true; } @@ -74,7 +64,7 @@ if (__DEV__) { 'Invalid event handler property `%s`. Did you mean `%s`?%s', name, registrationName, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -85,7 +75,7 @@ if (__DEV__) { false, 'Unknown event handler property `%s`. It will be ignored.%s', name, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -138,7 +128,7 @@ if (__DEV__) { 'Received a `%s` for string attribute `is`. If this is expected, cast ' + 'the value to a string.%s', typeof value, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -150,7 +140,7 @@ if (__DEV__) { 'Received NaN for numeric attribute `%s`. If this is expected, cast ' + 'the value to a string.%s', name, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -167,7 +157,7 @@ if (__DEV__) { 'Invalid DOM property `%s`. Did you mean `%s`?%s', name, standardName, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -184,7 +174,7 @@ if (__DEV__) { 'it from the DOM element.%s', name, lowerCasedName, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -197,7 +187,7 @@ if (__DEV__) { 'the value to a string.%s', value, name, - getStackAddendum(debugID), + getStackAddendum(), ); warnedProperties[name] = true; return true; @@ -219,10 +209,10 @@ if (__DEV__) { }; } -var warnUnknownProperties = function(type, props, debugID) { +var warnUnknownProperties = function(type, props) { var unknownProps = []; for (var key in props) { - var isValid = validateProperty(type, key, props[key], debugID); + var isValid = validateProperty(type, key, props[key]); if (!isValid) { unknownProps.push(key); } @@ -237,7 +227,7 @@ var warnUnknownProperties = function(type, props, debugID) { 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, - getStackAddendum(debugID), + getStackAddendum(), ); } else if (unknownProps.length > 1) { warning( @@ -247,32 +237,20 @@ var warnUnknownProperties = function(type, props, debugID) { 'For details, see https://fb.me/react-attribute-behavior%s', unknownPropString, type, - getStackAddendum(debugID), + getStackAddendum(), ); } }; -function validateProperties(type, props, debugID /* Stack only */) { +function validateProperties(type, props) { if (isCustomComponent(type, props)) { return; } - warnUnknownProperties(type, props, debugID); + warnUnknownProperties(type, props); } var ReactDOMUnknownPropertyHook = { - // Fiber validateProperties, - // Stack - onBeforeMountComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, - onBeforeUpdateComponent(debugID, element) { - if (__DEV__ && element != null && typeof element.type === 'string') { - validateProperties(element.type, element.props, debugID); - } - }, }; module.exports = ReactDOMUnknownPropertyHook; diff --git a/src/renderers/native/ReactNativeFiberEntry.js b/src/renderers/native/ReactNativeFiberEntry.js index 03617610c2b..b5ba64dbd3f 100644 --- a/src/renderers/native/ReactNativeFiberEntry.js +++ b/src/renderers/native/ReactNativeFiberEntry.js @@ -109,8 +109,19 @@ if (__DEV__) { Object.assign( ReactNativeFiber.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { - ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace - ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf + // TODO: none of these work since Fiber. Remove these dependencies. + // Used by RCTRenderingPerf, Systrace: + ReactDebugTool: { + addHook() {}, + removeHook() {}, + }, + // Used by ReactPerfStallHandler, RCTRenderingPerf: + ReactPerf: { + start() {}, + stop() {}, + printInclusive() {}, + printWasted() {}, + }, }, ); } diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js deleted file mode 100644 index 434157a0dd7..00000000000 --- a/src/renderers/shared/ReactDebugTool.js +++ /dev/null @@ -1,439 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactDebugTool - * @flow - */ - -'use strict'; - -var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook'); -var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook'); -var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); -var {ReactComponentTreeHook} = require('ReactGlobalSharedState'); - -var performanceNow = require('fbjs/lib/performanceNow'); - -if (__DEV__) { - var warning = require('fbjs/lib/warning'); -} - -import type {ReactElement} from 'ReactElementType'; -import type {DebugID} from 'ReactInstanceType'; -import type {Operation} from 'ReactHostOperationHistoryHook'; - -type Hook = any; - -type TimerType = - | 'ctor' - | 'render' - | 'componentWillMount' - | 'componentWillUnmount' - | 'componentWillReceiveProps' - | 'shouldComponentUpdate' - | 'componentWillUpdate' - | 'componentDidUpdate' - | 'componentDidMount'; - -type Measurement = { - timerType: TimerType, - instanceID: DebugID, - duration: number, -}; - -type TreeSnapshot = { - [key: DebugID]: { - displayName: string, - text: string, - updateCount: number, - childIDs: Array, - ownerID: DebugID, - parentID: DebugID, - }, -}; - -type HistoryItem = { - duration: number, - measurements: Array, - operations: Array, - treeSnapshot: TreeSnapshot, -}; - -export type FlushHistory = Array; - -// Trust the developer to only use this with a __DEV__ check -var ReactDebugTool = ((null: any): typeof ReactDebugTool); - -if (__DEV__) { - var hooks = []; - var didHookThrowForEvent = {}; - - const callHook = function(event, fn, context, arg1, arg2, arg3, arg4, arg5) { - try { - fn.call(context, arg1, arg2, arg3, arg4, arg5); - } catch (e) { - warning( - didHookThrowForEvent[event], - 'Exception thrown by hook while handling %s: %s', - event, - e + '\n' + e.stack, - ); - didHookThrowForEvent[event] = true; - } - }; - - const emitEvent = function(event, arg1, arg2, arg3, arg4, arg5) { - for (var i = 0; i < hooks.length; i++) { - var hook = hooks[i]; - var fn = hook[event]; - if (fn) { - callHook(event, fn, hook, arg1, arg2, arg3, arg4, arg5); - } - } - }; - - var isProfiling = false; - var flushHistory = []; - var lifeCycleTimerStack = []; - var currentFlushNesting = 0; - var currentFlushMeasurements = []; - var currentFlushStartTime = 0; - var currentTimerDebugID = null; - var currentTimerStartTime = 0; - var currentTimerNestedFlushDuration = 0; - var currentTimerType = null; - - var lifeCycleTimerHasWarned = false; - - const clearHistory = function() { - ReactComponentTreeHook.purgeUnmountedComponents(); - ReactHostOperationHistoryHook.clearHistory(); - }; - - const getTreeSnapshot = function(registeredIDs) { - return registeredIDs.reduce((tree, id) => { - var ownerID = ReactComponentTreeHook.getOwnerID(id); - var parentID = ReactComponentTreeHook.getParentID(id); - tree[id] = { - displayName: ReactComponentTreeHook.getDisplayName(id), - text: ReactComponentTreeHook.getText(id), - updateCount: ReactComponentTreeHook.getUpdateCount(id), - childIDs: ReactComponentTreeHook.getChildIDs(id), - // Text nodes don't have owners but this is close enough. - ownerID: ownerID || - (parentID && ReactComponentTreeHook.getOwnerID(parentID)) || - 0, - parentID, - }; - return tree; - }, {}); - }; - - const resetMeasurements = function() { - var previousStartTime = currentFlushStartTime; - var previousMeasurements = currentFlushMeasurements; - var previousOperations = ReactHostOperationHistoryHook.getHistory(); - - if (currentFlushNesting === 0) { - currentFlushStartTime = 0; - currentFlushMeasurements = []; - clearHistory(); - return; - } - - if (previousMeasurements.length || previousOperations.length) { - var registeredIDs = ReactComponentTreeHook.getRegisteredIDs(); - flushHistory.push({ - duration: performanceNow() - previousStartTime, - measurements: previousMeasurements || [], - operations: previousOperations || [], - treeSnapshot: getTreeSnapshot(registeredIDs), - }); - } - - clearHistory(); - currentFlushStartTime = performanceNow(); - currentFlushMeasurements = []; - }; - - const checkDebugID = function(debugID, allowRoot = false) { - if (allowRoot && debugID === 0) { - return; - } - if (!debugID) { - warning(false, 'ReactDebugTool: debugID may not be empty.'); - } - }; - - const beginLifeCycleTimer = function(debugID, timerType) { - if (currentFlushNesting === 0) { - return; - } - if (currentTimerType && !lifeCycleTimerHasWarned) { - warning( - false, - 'There is an internal error in the React performance measurement code.' + - '\n\nDid not expect %s timer to start while %s timer is still in ' + - 'progress for %s instance.', - timerType, - currentTimerType || 'no', - debugID === currentTimerDebugID ? 'the same' : 'another', - ); - lifeCycleTimerHasWarned = true; - } - currentTimerStartTime = performanceNow(); - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = debugID; - currentTimerType = timerType; - }; - - const endLifeCycleTimer = function(debugID, timerType) { - if (currentFlushNesting === 0) { - return; - } - if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) { - warning( - false, - 'There is an internal error in the React performance measurement code. ' + - 'We did not expect %s timer to stop while %s timer is still in ' + - 'progress for %s instance. Please report this as a bug in React.', - timerType, - currentTimerType || 'no', - debugID === currentTimerDebugID ? 'the same' : 'another', - ); - lifeCycleTimerHasWarned = true; - } - if (isProfiling) { - currentFlushMeasurements.push({ - timerType, - instanceID: debugID, - duration: performanceNow() - - currentTimerStartTime - - currentTimerNestedFlushDuration, - }); - } - currentTimerStartTime = 0; - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = null; - currentTimerType = null; - }; - - const pauseCurrentLifeCycleTimer = function() { - var currentTimer = { - startTime: currentTimerStartTime, - nestedFlushStartTime: performanceNow(), - debugID: currentTimerDebugID, - timerType: currentTimerType, - }; - lifeCycleTimerStack.push(currentTimer); - currentTimerStartTime = 0; - currentTimerNestedFlushDuration = 0; - currentTimerDebugID = null; - currentTimerType = null; - }; - - const resumeCurrentLifeCycleTimer = function() { - var { - startTime, - nestedFlushStartTime, - debugID, - timerType, - } = lifeCycleTimerStack.pop(); - var nestedFlushDuration = performanceNow() - nestedFlushStartTime; - currentTimerStartTime = startTime; - currentTimerNestedFlushDuration += nestedFlushDuration; - currentTimerDebugID = debugID; - currentTimerType = timerType; - }; - - var lastMarkTimeStamp = 0; - var canUsePerformanceMeasure: boolean = - typeof performance !== 'undefined' && - typeof performance.mark === 'function' && - typeof performance.clearMarks === 'function' && - typeof performance.measure === 'function' && - typeof performance.clearMeasures === 'function'; - - const shouldMark = function(debugID) { - if (!isProfiling || !canUsePerformanceMeasure) { - return false; - } - var element = ReactComponentTreeHook.getElement(debugID); - if (element == null || typeof element !== 'object') { - return false; - } - var isHostElement = typeof element.type === 'string'; - if (isHostElement) { - return false; - } - return true; - }; - - const markBegin = function(debugID, markType) { - if (!shouldMark(debugID)) { - return; - } - - var markName = `${debugID}::${markType}`; - lastMarkTimeStamp = performanceNow(); - performance.mark(markName); - }; - - const markEnd = function(debugID, markType) { - if (!shouldMark(debugID)) { - return; - } - - var markName = `${debugID}::${markType}`; - var displayName = - ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown'; - - // Chrome has an issue of dropping markers recorded too fast: - // https://bugs.chromium.org/p/chromium/issues/detail?id=640652 - // To work around this, we will not report very small measurements. - // I determined the magic number by tweaking it back and forth. - // 0.05ms was enough to prevent the issue, but I set it to 0.1ms to be safe. - // When the bug is fixed, we can `measure()` unconditionally if we want to. - var timeStamp = performanceNow(); - if (timeStamp - lastMarkTimeStamp > 0.1) { - var measurementName = `${displayName} [${markType}]`; - performance.measure(measurementName, markName); - } - - performance.clearMarks(markName); - if (measurementName) { - performance.clearMeasures(measurementName); - } - }; - - ReactDebugTool = { - addHook(hook: Hook): void { - hooks.push(hook); - }, - removeHook(hook: Hook): void { - for (var i = 0; i < hooks.length; i++) { - if (hooks[i] === hook) { - hooks.splice(i, 1); - i--; - } - } - }, - isProfiling(): boolean { - return isProfiling; - }, - beginProfiling(): void { - if (isProfiling) { - return; - } - - isProfiling = true; - flushHistory.length = 0; - resetMeasurements(); - ReactDebugTool.addHook(ReactHostOperationHistoryHook); - }, - endProfiling(): void { - if (!isProfiling) { - return; - } - - isProfiling = false; - resetMeasurements(); - ReactDebugTool.removeHook(ReactHostOperationHistoryHook); - }, - getFlushHistory(): FlushHistory { - return flushHistory; - }, - onBeginFlush(): void { - currentFlushNesting++; - resetMeasurements(); - pauseCurrentLifeCycleTimer(); - emitEvent('onBeginFlush'); - }, - onEndFlush(): void { - resetMeasurements(); - currentFlushNesting--; - resumeCurrentLifeCycleTimer(); - emitEvent('onEndFlush'); - }, - onBeginLifeCycleTimer(debugID: DebugID, timerType: TimerType): void { - checkDebugID(debugID); - emitEvent('onBeginLifeCycleTimer', debugID, timerType); - markBegin(debugID, timerType); - beginLifeCycleTimer(debugID, timerType); - }, - onEndLifeCycleTimer(debugID: DebugID, timerType: TimerType): void { - checkDebugID(debugID); - endLifeCycleTimer(debugID, timerType); - markEnd(debugID, timerType); - emitEvent('onEndLifeCycleTimer', debugID, timerType); - }, - onBeginProcessingChildContext(): void { - emitEvent('onBeginProcessingChildContext'); - }, - onEndProcessingChildContext(): void { - emitEvent('onEndProcessingChildContext'); - }, - onHostOperation(operation: Operation) { - checkDebugID(operation.instanceID); - emitEvent('onHostOperation', operation); - }, - onSetState(): void { - emitEvent('onSetState'); - }, - onSetChildren(debugID: DebugID, childDebugIDs: Array) { - checkDebugID(debugID); - childDebugIDs.forEach(checkDebugID); - emitEvent('onSetChildren', debugID, childDebugIDs); - }, - onBeforeMountComponent( - debugID: DebugID, - element: ReactElement, - parentDebugID: DebugID, - ): void { - checkDebugID(debugID); - checkDebugID(parentDebugID, true); - emitEvent('onBeforeMountComponent', debugID, element, parentDebugID); - markBegin(debugID, 'mount'); - }, - onMountComponent(debugID: DebugID): void { - checkDebugID(debugID); - markEnd(debugID, 'mount'); - emitEvent('onMountComponent', debugID); - }, - onBeforeUpdateComponent(debugID: DebugID, element: ReactElement): void { - checkDebugID(debugID); - emitEvent('onBeforeUpdateComponent', debugID, element); - markBegin(debugID, 'update'); - }, - onUpdateComponent(debugID: DebugID): void { - checkDebugID(debugID); - markEnd(debugID, 'update'); - emitEvent('onUpdateComponent', debugID); - }, - onBeforeUnmountComponent(debugID: DebugID): void { - checkDebugID(debugID); - emitEvent('onBeforeUnmountComponent', debugID); - markBegin(debugID, 'unmount'); - }, - onUnmountComponent(debugID: DebugID): void { - checkDebugID(debugID); - markEnd(debugID, 'unmount'); - emitEvent('onUnmountComponent', debugID); - }, - onTestEvent(): void { - emitEvent('onTestEvent'); - }, - }; - - ReactDebugTool.addHook(ReactInvalidSetStateWarningHook); - ReactDebugTool.addHook(ReactComponentTreeHook); - var url = (ExecutionEnvironment.canUseDOM && window.location.href) || ''; - if (/[?&]react_perf\b/.test(url)) { - ReactDebugTool.beginProfiling(); - } -} - -module.exports = ReactDebugTool; diff --git a/src/renderers/shared/ReactGlobalSharedState.js b/src/renderers/shared/ReactGlobalSharedState.js index 18cab35e252..3f922adf092 100644 --- a/src/renderers/shared/ReactGlobalSharedState.js +++ b/src/renderers/shared/ReactGlobalSharedState.js @@ -18,7 +18,6 @@ var ReactGlobalSharedState = { if (__DEV__) { Object.assign(ReactGlobalSharedState, { - ReactComponentTreeHook: ReactInternals.ReactComponentTreeHook, ReactDebugCurrentFrame: ReactInternals.ReactDebugCurrentFrame, }); } diff --git a/src/renderers/shared/ReactInstrumentation.js b/src/renderers/shared/ReactInstrumentation.js deleted file mode 100644 index f45f22f0990..00000000000 --- a/src/renderers/shared/ReactInstrumentation.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactInstrumentation - * @flow - */ - -'use strict'; - -// Trust the developer to only use ReactInstrumentation with a __DEV__ check -var debugTool = ((null: any): typeof ReactDebugTool); - -if (__DEV__) { - var ReactDebugTool = require('ReactDebugTool'); - debugTool = ReactDebugTool; -} - -module.exports = {debugTool}; diff --git a/src/renderers/shared/ReactPerf.js b/src/renderers/shared/ReactPerf.js deleted file mode 100644 index a35569d8e9a..00000000000 --- a/src/renderers/shared/ReactPerf.js +++ /dev/null @@ -1,456 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactPerf - * @flow - */ - -'use strict'; - -var ReactDebugTool = require('ReactDebugTool'); -var lowPriorityWarning = require('lowPriorityWarning'); -var alreadyWarned = false; - -import type {FlushHistory} from 'ReactDebugTool'; - -function roundFloat(val, base = 2) { - var n = Math.pow(10, base); - return Math.floor(val * n) / n; -} - -// Flow type definition of console.table is too strict right now, see -// https://github.com/facebook/flow/pull/2353 for updates -function consoleTable(table: Array<{[key: string]: any}>): void { - console.table((table: any)); -} - -function warnInProduction() { - if (alreadyWarned) { - return; - } - alreadyWarned = true; - if (typeof console !== 'undefined') { - console.error( - 'ReactPerf is not supported in the production builds of React. ' + - 'To collect measurements, please use the development build of React instead.', - ); - } -} - -function getLastMeasurements() { - if (!__DEV__) { - warnInProduction(); - return []; - } - - return ReactDebugTool.getFlushHistory(); -} - -function getExclusive(flushHistory = getLastMeasurements()) { - if (!__DEV__) { - warnInProduction(); - return []; - } - - var aggregatedStats = {}; - var affectedIDs = {}; - - function updateAggregatedStats( - treeSnapshot, - instanceID, - timerType, - applyUpdate, - ) { - var {displayName} = treeSnapshot[instanceID]; - var key = displayName; - var stats = aggregatedStats[key]; - if (!stats) { - affectedIDs[key] = {}; - stats = aggregatedStats[key] = { - key, - instanceCount: 0, - counts: {}, - durations: {}, - totalDuration: 0, - }; - } - if (!stats.durations[timerType]) { - stats.durations[timerType] = 0; - } - if (!stats.counts[timerType]) { - stats.counts[timerType] = 0; - } - affectedIDs[key][instanceID] = true; - applyUpdate(stats); - } - - flushHistory.forEach(flush => { - var {measurements, treeSnapshot} = flush; - measurements.forEach(measurement => { - var {duration, instanceID, timerType} = measurement; - updateAggregatedStats(treeSnapshot, instanceID, timerType, stats => { - stats.totalDuration += duration; - stats.durations[timerType] += duration; - stats.counts[timerType]++; - }); - }); - }); - - return Object.keys(aggregatedStats) - .map(key => ({ - ...aggregatedStats[key], - instanceCount: Object.keys(affectedIDs[key]).length, - })) - .sort((a, b) => b.totalDuration - a.totalDuration); -} - -function getInclusive(flushHistory = getLastMeasurements()) { - if (!__DEV__) { - warnInProduction(); - return []; - } - - var aggregatedStats = {}; - var affectedIDs = {}; - - function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) { - var {displayName, ownerID} = treeSnapshot[instanceID]; - var owner = treeSnapshot[ownerID]; - var key = (owner ? owner.displayName + ' > ' : '') + displayName; - var stats = aggregatedStats[key]; - if (!stats) { - affectedIDs[key] = {}; - stats = aggregatedStats[key] = { - key, - instanceCount: 0, - inclusiveRenderDuration: 0, - renderCount: 0, - }; - } - affectedIDs[key][instanceID] = true; - applyUpdate(stats); - } - - var isCompositeByID = {}; - flushHistory.forEach(flush => { - var {measurements} = flush; - measurements.forEach(measurement => { - var {instanceID, timerType} = measurement; - if (timerType !== 'render') { - return; - } - isCompositeByID[instanceID] = true; - }); - }); - - flushHistory.forEach(flush => { - var {measurements, treeSnapshot} = flush; - measurements.forEach(measurement => { - var {duration, instanceID, timerType} = measurement; - if (timerType !== 'render') { - return; - } - updateAggregatedStats(treeSnapshot, instanceID, stats => { - stats.renderCount++; - }); - var nextParentID = instanceID; - while (nextParentID) { - // As we traverse parents, only count inclusive time towards composites. - // We know something is a composite if its render() was called. - if (isCompositeByID[nextParentID]) { - updateAggregatedStats(treeSnapshot, nextParentID, stats => { - stats.inclusiveRenderDuration += duration; - }); - } - nextParentID = treeSnapshot[nextParentID].parentID; - } - }); - }); - - return Object.keys(aggregatedStats) - .map(key => ({ - ...aggregatedStats[key], - instanceCount: Object.keys(affectedIDs[key]).length, - })) - .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration); -} - -function getWasted(flushHistory = getLastMeasurements()) { - if (!__DEV__) { - warnInProduction(); - return []; - } - - var aggregatedStats = {}; - var affectedIDs = {}; - - function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) { - var {displayName, ownerID} = treeSnapshot[instanceID]; - var owner = treeSnapshot[ownerID]; - var key = (owner ? owner.displayName + ' > ' : '') + displayName; - var stats = aggregatedStats[key]; - if (!stats) { - affectedIDs[key] = {}; - stats = aggregatedStats[key] = { - key, - instanceCount: 0, - inclusiveRenderDuration: 0, - renderCount: 0, - }; - } - affectedIDs[key][instanceID] = true; - applyUpdate(stats); - } - - flushHistory.forEach(flush => { - var {measurements, treeSnapshot, operations} = flush; - var isDefinitelyNotWastedByID = {}; - - // Find host components associated with an operation in this batch. - // Mark all components in their parent tree as definitely not wasted. - operations.forEach(operation => { - var {instanceID} = operation; - var nextParentID = instanceID; - while (nextParentID) { - isDefinitelyNotWastedByID[nextParentID] = true; - nextParentID = treeSnapshot[nextParentID].parentID; - } - }); - - // Find composite components that rendered in this batch. - // These are potential candidates for being wasted renders. - var renderedCompositeIDs = {}; - measurements.forEach(measurement => { - var {instanceID, timerType} = measurement; - if (timerType !== 'render') { - return; - } - renderedCompositeIDs[instanceID] = true; - }); - - measurements.forEach(measurement => { - var {duration, instanceID, timerType} = measurement; - if (timerType !== 'render') { - return; - } - - // If there was a DOM update below this component, or it has just been - // mounted, its render() is not considered wasted. - var {updateCount} = treeSnapshot[instanceID]; - if (isDefinitelyNotWastedByID[instanceID] || updateCount === 0) { - return; - } - - // We consider this render() wasted. - updateAggregatedStats(treeSnapshot, instanceID, stats => { - stats.renderCount++; - }); - - var nextParentID = instanceID; - while (nextParentID) { - // Any parents rendered during this batch are considered wasted - // unless we previously marked them as dirty. - var isWasted = - renderedCompositeIDs[nextParentID] && - !isDefinitelyNotWastedByID[nextParentID]; - if (isWasted) { - updateAggregatedStats(treeSnapshot, nextParentID, stats => { - stats.inclusiveRenderDuration += duration; - }); - } - nextParentID = treeSnapshot[nextParentID].parentID; - } - }); - }); - - return Object.keys(aggregatedStats) - .map(key => ({ - ...aggregatedStats[key], - instanceCount: Object.keys(affectedIDs[key]).length, - })) - .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration); -} - -function getOperations(flushHistory = getLastMeasurements()) { - if (!__DEV__) { - warnInProduction(); - return []; - } - - var stats = []; - flushHistory.forEach((flush, flushIndex) => { - var {operations, treeSnapshot} = flush; - operations.forEach(operation => { - var {instanceID, type, payload} = operation; - var {displayName, ownerID} = treeSnapshot[instanceID]; - var owner = treeSnapshot[ownerID]; - var key = (owner ? owner.displayName + ' > ' : '') + displayName; - - stats.push({ - flushIndex, - instanceID, - key, - type, - ownerID, - payload, - }); - }); - }); - return stats; -} - -function printExclusive(flushHistory?: FlushHistory) { - if (!__DEV__) { - warnInProduction(); - return; - } - - var stats = getExclusive(flushHistory); - var table = stats.map(item => { - var {key, instanceCount, totalDuration} = item; - var renderCount = item.counts.render || 0; - var renderDuration = item.durations.render || 0; - return { - Component: key, - 'Total time (ms)': roundFloat(totalDuration), - 'Instance count': instanceCount, - 'Total render time (ms)': roundFloat(renderDuration), - 'Average render time (ms)': renderCount - ? roundFloat(renderDuration / renderCount) - : undefined, - 'Render count': renderCount, - 'Total lifecycle time (ms)': roundFloat(totalDuration - renderDuration), - }; - }); - consoleTable(table); -} - -function printInclusive(flushHistory?: FlushHistory) { - if (!__DEV__) { - warnInProduction(); - return; - } - - var stats = getInclusive(flushHistory); - var table = stats.map(item => { - var {key, instanceCount, inclusiveRenderDuration, renderCount} = item; - return { - 'Owner > Component': key, - 'Inclusive render time (ms)': roundFloat(inclusiveRenderDuration), - 'Instance count': instanceCount, - 'Render count': renderCount, - }; - }); - consoleTable(table); -} - -function printWasted(flushHistory?: FlushHistory) { - if (!__DEV__) { - warnInProduction(); - return; - } - - var stats = getWasted(flushHistory); - var table = stats.map(item => { - var {key, instanceCount, inclusiveRenderDuration, renderCount} = item; - return { - 'Owner > Component': key, - 'Inclusive wasted time (ms)': roundFloat(inclusiveRenderDuration), - 'Instance count': instanceCount, - 'Render count': renderCount, - }; - }); - consoleTable(table); -} - -function printOperations(flushHistory?: FlushHistory) { - if (!__DEV__) { - warnInProduction(); - return; - } - - var stats = getOperations(flushHistory); - var table = stats.map(stat => ({ - 'Owner > Node': stat.key, - Operation: stat.type, - Payload: typeof stat.payload === 'object' - ? JSON.stringify(stat.payload) - : stat.payload, - 'Flush index': stat.flushIndex, - 'Owner Component ID': stat.ownerID, - 'DOM Component ID': stat.instanceID, - })); - consoleTable(table); -} - -var warnedAboutPrintDOM = false; -function printDOM(measurements: FlushHistory) { - lowPriorityWarning( - warnedAboutPrintDOM, - '`ReactPerf.printDOM(...)` is deprecated. Use ' + - '`ReactPerf.printOperations(...)` instead.', - ); - warnedAboutPrintDOM = true; - return printOperations(measurements); -} - -var warnedAboutGetMeasurementsSummaryMap = false; -function getMeasurementsSummaryMap(measurements: FlushHistory) { - lowPriorityWarning( - warnedAboutGetMeasurementsSummaryMap, - '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' + - '`ReactPerf.getWasted(...)` instead.', - ); - warnedAboutGetMeasurementsSummaryMap = true; - return getWasted(measurements); -} - -function start() { - if (!__DEV__) { - warnInProduction(); - return; - } - - ReactDebugTool.beginProfiling(); -} - -function stop() { - if (!__DEV__) { - warnInProduction(); - return; - } - - ReactDebugTool.endProfiling(); -} - -function isRunning() { - if (!__DEV__) { - warnInProduction(); - return false; - } - - return ReactDebugTool.isProfiling(); -} - -var ReactPerfAnalysis = { - getLastMeasurements, - getExclusive, - getInclusive, - getWasted, - getOperations, - printExclusive, - printInclusive, - printWasted, - printOperations, - start, - stop, - isRunning, - // Deprecated: - printDOM, - getMeasurementsSummaryMap, -}; - -module.exports = ReactPerfAnalysis; diff --git a/src/renderers/shared/__tests__/ReactDebugTool-test.js b/src/renderers/shared/__tests__/ReactDebugTool-test.js deleted file mode 100644 index e7c0169a631..00000000000 --- a/src/renderers/shared/__tests__/ReactDebugTool-test.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -describe('ReactDebugTool', () => { - var ReactDebugTool; - - beforeEach(() => { - jest.resetModules(); - ReactDebugTool = require('ReactDebugTool'); - }); - - it('should add and remove hooks', () => { - var handler1 = jasmine.createSpy('spy'); - var handler2 = jasmine.createSpy('spy'); - var hook1 = {onTestEvent: handler1}; - var hook2 = {onTestEvent: handler2}; - - ReactDebugTool.addHook(hook1); - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(1); - expect(handler2.calls.count()).toBe(0); - - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(2); - expect(handler2.calls.count()).toBe(0); - - ReactDebugTool.addHook(hook2); - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(3); - expect(handler2.calls.count()).toBe(1); - - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(4); - expect(handler2.calls.count()).toBe(2); - - ReactDebugTool.removeHook(hook1); - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(4); - expect(handler2.calls.count()).toBe(3); - - ReactDebugTool.removeHook(hook2); - ReactDebugTool.onTestEvent(); - expect(handler1.calls.count()).toBe(4); - expect(handler2.calls.count()).toBe(3); - }); - - it('warns once when an error is thrown in hook', () => { - spyOn(console, 'error'); - ReactDebugTool.addHook({ - onTestEvent() { - throw new Error('Hi.'); - }, - }); - - ReactDebugTool.onTestEvent(); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toContain( - 'Exception thrown by hook while handling ' + 'onTestEvent: Error: Hi.', - ); - - ReactDebugTool.onTestEvent(); - expectDev(console.error.calls.count()).toBe(1); - }); - - it('returns isProfiling state', () => { - expect(ReactDebugTool.isProfiling()).toBe(false); - - ReactDebugTool.beginProfiling(); - expect(ReactDebugTool.isProfiling()).toBe(true); - - ReactDebugTool.endProfiling(); - expect(ReactDebugTool.isProfiling()).toBe(false); - }); -}); diff --git a/src/test/ReactComponentTreeTestUtils.js b/src/test/ReactComponentTreeTestUtils.js deleted file mode 100644 index fde437d8520..00000000000 --- a/src/test/ReactComponentTreeTestUtils.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactComponentTreeTestUtils - */ - -'use strict'; - -var ReactComponentTreeHook = require('ReactComponentTreeHook'); - -function getRootDisplayNames() { - return ReactComponentTreeHook.getRootIDs().map( - ReactComponentTreeHook.getDisplayName, - ); -} - -function getRegisteredDisplayNames() { - return ReactComponentTreeHook.getRegisteredIDs().map( - ReactComponentTreeHook.getDisplayName, - ); -} - -function expectTree(rootID, expectedTree, parentPath) { - var displayName = ReactComponentTreeHook.getDisplayName(rootID); - var ownerID = ReactComponentTreeHook.getOwnerID(rootID); - var parentID = ReactComponentTreeHook.getParentID(rootID); - var childIDs = ReactComponentTreeHook.getChildIDs(rootID); - var text = ReactComponentTreeHook.getText(rootID); - var element = ReactComponentTreeHook.getElement(rootID); - var path = parentPath ? `${parentPath} > ${displayName}` : displayName; - - function expectEqual(actual, expected, name) { - // Get Jasmine to print descriptive error messages. - // We pass path so that we know where the mismatch occurred. - expectDev({ - path, - [name]: actual, - }).toEqual({ - path, - [name]: expected, - }); - } - - if (expectedTree.parentDisplayName !== undefined) { - expectEqual( - ReactComponentTreeHook.getDisplayName(parentID), - expectedTree.parentDisplayName, - 'parentDisplayName', - ); - } - if (expectedTree.ownerDisplayName !== undefined) { - expectEqual( - ReactComponentTreeHook.getDisplayName(ownerID), - expectedTree.ownerDisplayName, - 'ownerDisplayName', - ); - } - if (expectedTree.parentID !== undefined) { - expectEqual(parentID, expectedTree.parentID, 'parentID'); - } - if (expectedTree.text !== undefined) { - expectEqual(text, expectedTree.text, 'text'); - expectEqual('' + element, expectedTree.text, 'element.toString()'); - } else { - expectEqual(text, null, 'text'); - } - if (expectedTree.element !== undefined) { - // TODO: Comparing elements makes tests run out of memory on errors. - // For now, compare just types. - expectEqual( - element && element.type, - expectedTree.element && expectedTree.element.type, - 'element.type', - ); - } else if (text == null) { - expectEqual(typeof element, 'object', 'typeof element'); - } - if (expectedTree.children !== undefined) { - expectEqual( - childIDs.length, - expectedTree.children.length, - 'children.length', - ); - for (var i = 0; i < childIDs.length; i++) { - expectTree( - childIDs[i], - {parentID: rootID, ...expectedTree.children[i]}, - path, - ); - } - } else { - expectEqual(childIDs, [], 'childIDs'); - } -} - -var ReactComponentTreeTestUtils = { - expectTree, - getRootDisplayNames, - getRegisteredDisplayNames, -}; - -module.exports = ReactComponentTreeTestUtils;