@samitouri / QOS-React / commits / 745c4ab0af

Remove Stack-only DEV code (#10797)

Dan Abramov committed Oct 2, 2017 at 11:42 UTC 745c4ab0af92d9510a6373a0985acf04bf865384
16 files changed +51 -5297
src/isomorphic/ReactEntry.js
-1
@@ -58,7 +58,6 @@ var React = {
58 if (__DEV__) {
59 Object.assign(React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, {
60 // These should not be included in production.
61 - ReactComponentTreeHook: require('ReactComponentTreeHook'),
61 ReactDebugCurrentFrame: require('ReactDebugCurrentFrame'),
62 });
63 }
src/isomorphic/hooks/ReactComponentTreeHook.js deleted
-396
@@ -1,396 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - * @providesModule ReactComponentTreeHook
9 - */
10 -
11 -'use strict';
12 -
13 -var ReactCurrentOwner = require('ReactCurrentOwner');
14 -var invariant = require('fbjs/lib/invariant');
15 -var describeComponentFrame = require('describeComponentFrame');
16 -
17 -if (__DEV__) {
18 - var warning = require('fbjs/lib/warning');
19 -}
20 -
21 -import type {ReactElement, Source} from 'ReactElementType';
22 -import type {DebugID} from 'ReactInstanceType';
23 -
24 -function isNative(fn) {
25 - // Based on isNative() from Lodash
26 - var funcToString = Function.prototype.toString;
27 - var reIsNative = RegExp(
28 - '^' +
29 - funcToString
30 - // Take an example native function source for comparison
31 - .call(Object.prototype.hasOwnProperty)
32 - // Strip regex characters so we can use it for regex
33 - .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
34 - // Remove hasOwnProperty from the template to make it generic
35 - .replace(
36 - /hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
37 - '$1.*?',
38 - ) +
39 - '$',
40 - );
41 - try {
42 - var source = funcToString.call(fn);
43 - return reIsNative.test(source);
44 - } catch (err) {
45 - return false;
46 - }
47 -}
48 -
49 -var canUseCollections =
50 - // Array.from
51 - typeof Array.from === 'function' &&
52 - // Map
53 - typeof Map === 'function' &&
54 - isNative(Map) &&
55 - // Map.prototype.keys
56 - Map.prototype != null &&
57 - typeof Map.prototype.keys === 'function' &&
58 - isNative(Map.prototype.keys) &&
59 - // Set
60 - typeof Set === 'function' &&
61 - isNative(Set) &&
62 - // Set.prototype.keys
63 - Set.prototype != null &&
64 - typeof Set.prototype.keys === 'function' &&
65 - isNative(Set.prototype.keys);
66 -
67 -var setItem;
68 -var getItem;
69 -var removeItem;
70 -var getItemIDs;
71 -var addRoot;
72 -var removeRoot;
73 -var getRootIDs;
74 -
75 -if (canUseCollections) {
76 - var itemMap = new Map();
77 - var rootIDSet = new Set();
78 -
79 - setItem = function(id, item) {
80 - itemMap.set(id, item);
81 - };
82 - getItem = function(id) {
83 - return itemMap.get(id);
84 - };
85 - removeItem = function(id) {
86 - itemMap.delete(id);
87 - };
88 - getItemIDs = function() {
89 - return Array.from(itemMap.keys());
90 - };
91 -
92 - addRoot = function(id) {
93 - rootIDSet.add(id);
94 - };
95 - removeRoot = function(id) {
96 - rootIDSet.delete(id);
97 - };
98 - getRootIDs = function() {
99 - return Array.from(rootIDSet.keys());
100 - };
101 -} else {
102 - var itemByKey = {};
103 - var rootByKey = {};
104 -
105 - // Use non-numeric keys to prevent V8 performance issues:
106 - // https://github.com/facebook/react/pull/7232
107 - var getKeyFromID = function(id: DebugID): string {
108 - return '.' + id;
109 - };
110 - var getIDFromKey = function(key: string): DebugID {
111 - return parseInt(key.substr(1), 10);
112 - };
113 -
114 - setItem = function(id, item) {
115 - var key = getKeyFromID(id);
116 - itemByKey[key] = item;
117 - };
118 - getItem = function(id) {
119 - var key = getKeyFromID(id);
120 - return itemByKey[key];
121 - };
122 - removeItem = function(id) {
123 - var key = getKeyFromID(id);
124 - delete itemByKey[key];
125 - };
126 - getItemIDs = function() {
127 - return Object.keys(itemByKey).map(getIDFromKey);
128 - };
129 -
130 - addRoot = function(id) {
131 - var key = getKeyFromID(id);
132 - rootByKey[key] = true;
133 - };
134 - removeRoot = function(id) {
135 - var key = getKeyFromID(id);
136 - delete rootByKey[key];
137 - };
138 - getRootIDs = function() {
139 - return Object.keys(rootByKey).map(getIDFromKey);
140 - };
141 -}
142 -
143 -var unmountedIDs: Array<DebugID> = [];
144 -
145 -function purgeDeep(id) {
146 - var item = getItem(id);
147 - if (item) {
148 - var {childIDs} = item;
149 - removeItem(id);
150 - childIDs.forEach(purgeDeep);
151 - }
152 -}
153 -
154 -function getDisplayName(element: ?ReactElement): string {
155 - if (element == null) {
156 - return '#empty';
157 - } else if (typeof element === 'string' || typeof element === 'number') {
158 - return '#text';
159 - } else if (typeof element.type === 'string') {
160 - return element.type;
161 - } else {
162 - return element.type.displayName || element.type.name || 'Unknown';
163 - }
164 -}
165 -
166 -function describeID(id: DebugID): string {
167 - const name = ReactComponentTreeHook.getDisplayName(id);
168 - const element = ReactComponentTreeHook.getElement(id);
169 - const ownerID = ReactComponentTreeHook.getOwnerID(id);
170 - let ownerName;
171 -
172 - if (ownerID) {
173 - ownerName = ReactComponentTreeHook.getDisplayName(ownerID);
174 - }
175 - warning(
176 - element,
177 - 'ReactComponentTreeHook: Missing React element for debugID %s when ' +
178 - 'building stack',
179 - id,
180 - );
181 - return describeComponentFrame(
182 - name || '',
183 - element && element._source,
184 - ownerName || '',
185 - );
186 -}
187 -
188 -var ReactComponentTreeHook = {
189 - onSetChildren(id: DebugID, nextChildIDs: Array<DebugID>): void {
190 - var item = getItem(id);
191 - invariant(item, 'Item must have been set');
192 - item.childIDs = nextChildIDs;
193 -
194 - for (var i = 0; i < nextChildIDs.length; i++) {
195 - var nextChildID = nextChildIDs[i];
196 - var nextChild = getItem(nextChildID);
197 - invariant(
198 - nextChild,
199 - 'Expected hook events to fire for the child ' +
200 - 'before its parent includes it in onSetChildren().',
201 - );
202 - invariant(
203 - nextChild.childIDs != null ||
204 - typeof nextChild.element !== 'object' ||
205 - nextChild.element == null,
206 - 'Expected onSetChildren() to fire for a container child ' +
207 - 'before its parent includes it in onSetChildren().',
208 - );
209 - invariant(
210 - nextChild.isMounted,
211 - 'Expected onMountComponent() to fire for the child ' +
212 - 'before its parent includes it in onSetChildren().',
213 - );
214 - if (nextChild.parentID == null) {
215 - nextChild.parentID = id;
216 - // TODO: This shouldn't be necessary but mounting a new root during in
217 - // componentWillMount currently causes not-yet-mounted components to
218 - // be purged from our tree data so their parent id is missing.
219 - }
220 - invariant(
221 - nextChild.parentID === id,
222 - 'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
223 - 'be consistent (%s has parents %s and %s).',
224 - nextChildID,
225 - nextChild.parentID,
226 - id,
227 - );
228 - }
229 - },
230 -
231 - onBeforeMountComponent(
232 - id: DebugID,
233 - element: ReactElement,
234 - parentID: DebugID,
235 - ): void {
236 - var item = {
237 - element,
238 - parentID,
239 - text: null,
240 - childIDs: [],
241 - isMounted: false,
242 - updateCount: 0,
243 - };
244 - setItem(id, item);
245 - },
246 -
247 - onBeforeUpdateComponent(id: DebugID, element: ReactElement): void {
248 - var item = getItem(id);
249 - if (!item || !item.isMounted) {
250 - // We may end up here as a result of setState() in componentWillUnmount().
251 - // In this case, ignore the element.
252 - return;
253 - }
254 - item.element = element;
255 - },
256 -
257 - onMountComponent(id: DebugID): void {
258 - var item = getItem(id);
259 - invariant(item, 'Item must have been set');
260 - item.isMounted = true;
261 - var isRoot = item.parentID === 0;
262 - if (isRoot) {
263 - addRoot(id);
264 - }
265 - },
266 -
267 - onUpdateComponent(id: DebugID): void {
268 - var item = getItem(id);
269 - if (!item || !item.isMounted) {
270 - // We may end up here as a result of setState() in componentWillUnmount().
271 - // In this case, ignore the element.
272 - return;
273 - }
274 - item.updateCount++;
275 - },
276 -
277 - onUnmountComponent(id: DebugID): void {
278 - var item = getItem(id);
279 - if (item) {
280 - // We need to check if it exists.
281 - // `item` might not exist if it is inside an error boundary, and a sibling
282 - // error boundary child threw while mounting. Then this instance never
283 - // got a chance to mount, but it still gets an unmounting event during
284 - // the error boundary cleanup.
285 - item.isMounted = false;
286 - var isRoot = item.parentID === 0;
287 - if (isRoot) {
288 - removeRoot(id);
289 - }
290 - }
291 - unmountedIDs.push(id);
292 - },
293 -
294 - purgeUnmountedComponents(): void {
295 - if (ReactComponentTreeHook._preventPurging) {
296 - // Should only be used for testing.
297 - return;
298 - }
299 -
300 - for (var i = 0; i < unmountedIDs.length; i++) {
301 - var id = unmountedIDs[i];
302 - purgeDeep(id);
303 - }
304 - unmountedIDs.length = 0;
305 - },
306 -
307 - isMounted(id: DebugID): boolean {
308 - var item = getItem(id);
309 - return item ? item.isMounted : false;
310 - },
311 -
312 - getCurrentStackAddendum(): string {
313 - var info = '';
314 - var currentOwner = ReactCurrentOwner.current;
315 - if (currentOwner) {
316 - invariant(
317 - typeof currentOwner.tag !== 'number',
318 - 'Fiber owners should not show up in Stack stack traces.',
319 - );
320 - if (typeof currentOwner._debugID === 'number') {
321 - info += ReactComponentTreeHook.getStackAddendumByID(
322 - currentOwner._debugID,
323 - );
324 - }
325 - }
326 - return info;
327 - },
328 -
329 - getStackAddendumByID(id: ?DebugID): string {
330 - var info = '';
331 - while (id) {
332 - info += describeID(id);
333 - id = ReactComponentTreeHook.getParentID(id);
334 - }
335 - return info;
336 - },
337 -
338 - getChildIDs(id: DebugID): Array<DebugID> {
339 - var item = getItem(id);
340 - return item ? item.childIDs : [];
341 - },
342 -
343 - getDisplayName(id: DebugID): ?string {
344 - var element = ReactComponentTreeHook.getElement(id);
345 - if (!element) {
346 - return null;
347 - }
348 - return getDisplayName(element);
349 - },
350 -
351 - getElement(id: DebugID): ?ReactElement {
352 - var item = getItem(id);
353 - return item ? item.element : null;
354 - },
355 -
356 - getOwnerID(id: DebugID): ?DebugID {
357 - var element = ReactComponentTreeHook.getElement(id);
358 - if (!element || !element._owner) {
359 - return null;
360 - }
361 - return element._owner._debugID;
362 - },
363 -
364 - getParentID(id: DebugID): ?DebugID {
365 - var item = getItem(id);
366 - return item ? item.parentID : null;
367 - },
368 -
369 - getSource(id: DebugID): ?Source {
370 - var item = getItem(id);
371 - var element = item ? item.element : null;
372 - var source = element != null ? element._source : null;
373 - return source;
374 - },
375 -
376 - getText(id: DebugID): ?string {
377 - var element = ReactComponentTreeHook.getElement(id);
378 - if (typeof element === 'string') {
379 - return element;
380 - } else if (typeof element === 'number') {
381 - return '' + element;
382 - } else {
383 - return null;
384 - }
385 - },
386 -
387 - getUpdateCount(id: DebugID): number {
388 - var item = getItem(id);
389 - return item ? item.updateCount : 0;
390 - },
391 -
392 - getRootIDs,
393 - getRegisteredIDs: getItemIDs,
394 -};
395 -
396 -module.exports = ReactComponentTreeHook;
src/renderers/__tests__/ReactComponentTreeHook-test.js deleted
-2146
@@ -1,2146 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -describe.skip('ReactComponentTreeHook', () => {
13 - var React;
14 - var ReactDOM;
15 - var ReactInstanceMap;
16 - var ReactComponentTreeHook;
17 - var ReactDebugCurrentFiber;
18 - var ReactComponentTreeTestUtils;
19 -
20 - beforeEach(() => {
21 - jest.resetModules();
22 -
23 - React = require('react');
24 - ReactDOM = require('react-dom');
25 - ReactInstanceMap = require('ReactInstanceMap');
26 - ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
27 - ReactComponentTreeHook = require('ReactComponentTreeHook');
28 - ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
29 - });
30 -
31 - // This is the only part used both by Stack and Fiber.
32 - describe('stack addenda', () => {
33 - it('gets created', () => {
34 - function getAddendum(element) {
35 - var addendum =
36 - ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || '';
37 - return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
38 - }
39 -
40 - function Anon() {
41 - return null;
42 - }
43 - Object.defineProperty(Anon, 'name', {
44 - value: null,
45 - });
46 - // function Orange() {
47 - // return null;
48 - // }
49 -
50 - expectDev(getAddendum()).toBe('');
51 - // expectDev(getAddendum(<div />)).toBe('\n in div (at **)');
52 - // expectDev(getAddendum(<Anon />)).toBe('\n in Unknown (at **)');
53 - // expectDev(getAddendum(<Orange />)).toBe('\n in Orange (at **)');
54 - // expectDev(getAddendum(React.createElement(Orange))).toBe(
55 - // '\n in Orange',
56 - // );
57 -
58 - var renders = 0;
59 - //var rOwnedByQ;
60 -
61 - function Q() {
62 - return /*rOwnedByQ =*/ React.createElement(R);
63 - }
64 - function R() {
65 - return <div><S /></div>;
66 - }
67 - class S extends React.Component {
68 - componentDidMount() {
69 - // Check that the parent path is still fetched when only S itself is on
70 - // the stack.
71 - this.forceUpdate();
72 - }
73 - render() {
74 - expectDev(getAddendum()).toBe(
75 - '\n in S (at **)' +
76 - '\n in div (at **)' +
77 - '\n in R (created by Q)' +
78 - '\n in Q (at **)',
79 - );
80 - expectDev(getAddendum(<span />)).toBe(
81 - // '\n in span (at **)' +
82 - '\n in S (at **)' +
83 - '\n in div (at **)' +
84 - '\n in R (created by Q)' +
85 - '\n in Q (at **)',
86 - );
87 - expectDev(getAddendum(React.createElement('span'))).toBe(
88 - // '\n in span (created by S)' +
89 - '\n in S (at **)' +
90 - '\n in div (at **)' +
91 - '\n in R (created by Q)' +
92 - '\n in Q (at **)',
93 - );
94 - renders++;
95 - return null;
96 - }
97 - }
98 - ReactDOM.render(<Q />, document.createElement('div'));
99 - expectDev(renders).toBe(2);
100 -
101 - // Make sure owner is fetched for the top element too.
102 - // expectDev(getAddendum(rOwnedByQ)).toBe('\n in R (created by Q)');
103 - });
104 - });
105 -
106 - // The rest of this file is not relevant for Fiber.
107 - // TODO: remove tests below when we delete Stack.
108 -
109 - function assertTreeMatches(pairs) {
110 - if (!Array.isArray(pairs[0])) {
111 - pairs = [pairs];
112 - }
113 -
114 - var node = document.createElement('div');
115 - var currentElement;
116 - var rootInstance;
117 -
118 - class Wrapper extends React.Component {
119 - render() {
120 - rootInstance = ReactInstanceMap.get(this);
121 - return currentElement;
122 - }
123 - }
124 -
125 - function expectWrapperTreeToEqual(expectedTree, andStayMounted) {
126 - ReactComponentTreeTestUtils.expectTree(rootInstance._debugID, {
127 - displayName: 'Wrapper',
128 - children: expectedTree ? [expectedTree] : [],
129 - });
130 - var rootDisplayNames = ReactComponentTreeTestUtils.getRootDisplayNames();
131 - var registeredDisplayNames = ReactComponentTreeTestUtils.getRegisteredDisplayNames();
132 - if (!expectedTree) {
133 - expectDev(rootDisplayNames).toEqual([]);
134 - expectDev(registeredDisplayNames).toEqual([]);
135 - } else if (andStayMounted) {
136 - expectDev(rootDisplayNames).toContain('Wrapper');
137 - expectDev(registeredDisplayNames).toContain('Wrapper');
138 - }
139 - }
140 -
141 - // Mount once, render updates, then unmount.
142 - // Ensure the tree is correct on every step.
143 - pairs.forEach(([element, expectedTree]) => {
144 - currentElement = element;
145 -
146 - // Mount a new tree or update the existing tree.
147 - ReactDOM.render(<Wrapper />, node);
148 - expectWrapperTreeToEqual(expectedTree, true);
149 -
150 - // Purging should have no effect
151 - // on the tree we expect to see.
152 - ReactComponentTreeHook.purgeUnmountedComponents();
153 - expectWrapperTreeToEqual(expectedTree, true);
154 - });
155 -
156 - // Unmounting the root node should purge
157 - // the whole subtree automatically.
158 - ReactDOM.unmountComponentAtNode(node);
159 - expectWrapperTreeToEqual(null);
160 - }
161 -
162 - describe('mount', () => {
163 - it('uses displayName or Unknown for classic components', () => {
164 - class Foo extends React.Component {
165 - render() {
166 - return null;
167 - }
168 - }
169 -
170 - Foo.displayName = 'Bar';
171 -
172 - class Baz extends React.Component {
173 - render() {
174 - return null;
175 - }
176 - }
177 -
178 - class Qux extends React.Component {
179 - render() {
180 - return null;
181 - }
182 - }
183 -
184 - delete Qux.displayName;
185 -
186 - var element = <div><Foo /><Baz /><Qux /></div>;
187 - var tree = {
188 - displayName: 'div',
189 - children: [
190 - {
191 - displayName: 'Bar',
192 - children: [],
193 - },
194 - {
195 - displayName: 'Baz',
196 - children: [],
197 - },
198 - {
199 - displayName: 'Unknown',
200 - children: [],
201 - },
202 - ],
203 - };
204 - assertTreeMatches([element, tree]);
205 - });
206 -
207 - it('uses displayName, name, or ReactComponent for modern components', () => {
208 - class Foo extends React.Component {
209 - render() {
210 - return null;
211 - }
212 - }
213 - Foo.displayName = 'Bar';
214 - class Baz extends React.Component {
215 - render() {
216 - return null;
217 - }
218 - }
219 - class Qux extends React.Component {
220 - render() {
221 - return null;
222 - }
223 - }
224 - delete Qux.name;
225 -
226 - var element = <div><Foo /><Baz /><Qux /></div>;
227 - var tree = {
228 - displayName: 'div',
229 - element,
230 - children: [
231 - {
232 - displayName: 'Bar',
233 - children: [],
234 - },
235 - {
236 - displayName: 'Baz',
237 - children: [],
238 - },
239 - {
240 - // Note: Ideally fallback name should be consistent (e.g. "Unknown")
241 - displayName: 'ReactComponent',
242 - children: [],
243 - },
244 - ],
245 - };
246 - assertTreeMatches([element, tree]);
247 - });
248 -
249 - it('uses displayName, name, or Object for factory components', () => {
250 - function Foo() {
251 - return {
252 - render() {
253 - return null;
254 - },
255 - };
256 - }
257 - Foo.displayName = 'Bar';
258 - function Baz() {
259 - return {
260 - render() {
261 - return null;
262 - },
263 - };
264 - }
265 - function Qux() {
266 - return {
267 - render() {
268 - return null;
269 - },
270 - };
271 - }
272 - delete Qux.name;
273 -
274 - var element = <div><Foo /><Baz /><Qux /></div>;
275 - var tree = {
276 - displayName: 'div',
277 - element,
278 - children: [
279 - {
280 - displayName: 'Bar',
281 - children: [],
282 - },
283 - {
284 - displayName: 'Baz',
285 - children: [],
286 - },
287 - {
288 - displayName: 'Unknown',
289 - children: [],
290 - },
291 - ],
292 - };
293 - assertTreeMatches([element, tree]);
294 - });
295 -
296 - it('uses displayName, name, or StatelessComponent for functional components', () => {
297 - function Foo() {
298 - return null;
299 - }
300 - Foo.displayName = 'Bar';
301 - function Baz() {
302 - return null;
303 - }
304 - function Qux() {
305 - return null;
306 - }
307 - delete Qux.name;
308 -
309 - var element = <div><Foo /><Baz /><Qux /></div>;
310 - var tree = {
311 - displayName: 'div',
312 - element,
313 - children: [
314 - {
315 - displayName: 'Bar',
316 - children: [],
317 - },
318 - {
319 - displayName: 'Baz',
320 - children: [],
321 - },
322 - {
323 - displayName: 'Unknown',
324 - children: [],
325 - },
326 - ],
327 - };
328 - assertTreeMatches([element, tree]);
329 - });
330 -
331 - it('reports a host tree correctly', () => {
332 - var element = (
333 - <div>
334 - <p>
335 - <span>
336 - Hi!
337 - </span>
338 - Wow.
339 - </p>
340 - <hr />
341 - </div>
342 - );
343 - var tree = {
344 - displayName: 'div',
345 - children: [
346 - {
347 - displayName: 'p',
348 - children: [
349 - {
350 - displayName: 'span',
351 - children: [
352 - {
353 - displayName: '#text',
354 - text: 'Hi!',
355 - },
356 - ],
357 - },
358 - {
359 - displayName: '#text',
360 - text: 'Wow.',
361 - },
362 - ],
363 - },
364 - {
365 - displayName: 'hr',
366 - element: <hr />,
367 - children: [],
368 - },
369 - ],
370 - };
371 - assertTreeMatches([element, tree]);
372 - });
373 -
374 - it('reports a simple tree with composites correctly', () => {
375 - class Foo extends React.Component {
376 - render() {
377 - return <div />;
378 - }
379 - }
380 -
381 - var element = <Foo />;
382 - var tree = {
383 - displayName: 'Foo',
384 - element,
385 - children: [
386 - {
387 - displayName: 'div',
388 - element: <div />,
389 - children: [],
390 - },
391 - ],
392 - };
393 - assertTreeMatches([element, tree]);
394 - });
395 -
396 - it('reports a tree with composites correctly', () => {
397 - class Qux extends React.Component {
398 - render() {
399 - return null;
400 - }
401 - }
402 -
403 - function Foo() {
404 - return {
405 - render() {
406 - return <Qux />;
407 - },
408 - };
409 - }
410 - function Bar({children}) {
411 - return <h1>{children}</h1>;
412 - }
413 - class Baz extends React.Component {
414 - render() {
415 - return (
416 - <div>
417 - <Foo />
418 - <Bar>
419 - <span>Hi,</span>
420 - Mom
421 - </Bar>
422 - <a href="#">Click me.</a>
423 - </div>
424 - );
425 - }
426 - }
427 -
428 - var element = <Baz />;
429 - var tree = {
430 - displayName: 'Baz',
431 - element,
432 - children: [
433 - {
434 - displayName: 'div',
435 - children: [
436 - {
437 - displayName: 'Foo',
438 - element: <Foo />,
439 - children: [
440 - {
441 - displayName: 'Qux',
442 - element: <Qux />,
443 - children: [],
444 - },
445 - ],
446 - },
447 - {
448 - displayName: 'Bar',
449 - children: [
450 - {
451 - displayName: 'h1',
452 - children: [
453 - {
454 - displayName: 'span',
455 - children: [
456 - {
457 - displayName: '#text',
458 - element: 'Hi,',
459 - text: 'Hi,',
460 - },
461 - ],
462 - },
463 - {
464 - displayName: '#text',
465 - text: 'Mom',
466 - element: 'Mom',
467 - },
468 - ],
469 - },
470 - ],
471 - },
472 - {
473 - displayName: 'a',
474 - children: [
475 - {
476 - displayName: '#text',
477 - text: 'Click me.',
478 - element: 'Click me.',
479 - },
480 - ],
481 - },
482 - ],
483 - },
484 - ],
485 - };
486 - assertTreeMatches([element, tree]);
487 - });
488 -
489 - it('ignores null children', () => {
490 - class Foo extends React.Component {
491 - render() {
492 - return null;
493 - }
494 - }
495 - var element = <Foo />;
496 - var tree = {
497 - displayName: 'Foo',
498 - children: [],
499 - };
500 - assertTreeMatches([element, tree]);
501 - });
502 -
503 - it('ignores false children', () => {
504 - class Foo extends React.Component {
505 - render() {
506 - return false;
507 - }
508 - }
509 - var element = <Foo />;
510 - var tree = {
511 - displayName: 'Foo',
512 - children: [],
513 - };
514 - assertTreeMatches([element, tree]);
515 - });
516 -
517 - it('reports text nodes as children', () => {
518 - var element = <div>{'1'}{2}</div>;
519 - var tree = {
520 - displayName: 'div',
521 - element,
522 - children: [
523 - {
524 - displayName: '#text',
525 - text: '1',
526 - },
527 - {
528 - displayName: '#text',
529 - text: '2',
530 - },
531 - ],
532 - };
533 - assertTreeMatches([element, tree]);
534 - });
535 -
536 - it('reports a single text node as a child', () => {
537 - var element = <div>{'1'}</div>;
538 - var tree = {
539 - displayName: 'div',
540 - element,
541 - children: [
542 - {
543 - displayName: '#text',
544 - text: '1',
545 - },
546 - ],
547 - };
548 - assertTreeMatches([element, tree]);
549 - });
550 -
551 - it('reports a single number node as a child', () => {
552 - var element = <div>{42}</div>;
553 - var tree = {
554 - displayName: 'div',
555 - element,
556 - children: [
557 - {
558 - displayName: '#text',
559 - text: '42',
560 - },
561 - ],
562 - };
563 - assertTreeMatches([element, tree]);
564 - });
565 -
566 - it('reports a zero as a child', () => {
567 - var element = <div>{0}</div>;
568 - var tree = {
569 - displayName: 'div',
570 - element,
571 - children: [
572 - {
573 - displayName: '#text',
574 - text: '0',
575 - },
576 - ],
577 - };
578 - assertTreeMatches([element, tree]);
579 - });
580 -
581 - it('skips empty nodes for multiple children', () => {
582 - function Foo() {
583 - return <div />;
584 - }
585 - var element = (
586 - <div>
587 - {'hi'}
588 - {false}
589 - {42}
590 - {null}
591 - <Foo />
592 - </div>
593 - );
594 - var tree = {
595 - displayName: 'div',
596 - element,
597 - children: [
598 - {
599 - displayName: '#text',
600 - text: 'hi',
601 - element: 'hi',
602 - },
603 - {
604 - displayName: '#text',
605 - text: '42',
606 - element: 42,
607 - },
608 - {
609 - displayName: 'Foo',
610 - element: <Foo />,
611 - children: [
612 - {
613 - displayName: 'div',
614 - element: <div />,
615 - children: [],
616 - },
617 - ],
618 - },
619 - ],
620 - };
621 - assertTreeMatches([element, tree]);
622 - });
623 -
624 - it('reports html content as no children', () => {
625 - var element = <div dangerouslySetInnerHTML={{__html: 'Bye.'}} />;
626 - var tree = {
627 - displayName: 'div',
628 - children: [],
629 - };
630 - assertTreeMatches([element, tree]);
631 - });
632 - });
633 -
634 - describe('update', () => {
635 - describe('host component', () => {
636 - it('updates text of a single text child', () => {
637 - var elementBefore = <div>Hi.</div>;
638 - var treeBefore = {
639 - displayName: 'div',
640 - children: [
641 - {
642 - displayName: '#text',
643 - text: 'Hi.',
644 - },
645 - ],
646 - };
647 -
648 - var elementAfter = <div>Bye.</div>;
649 - var treeAfter = {
650 - displayName: 'div',
651 - children: [
652 - {
653 - displayName: '#text',
654 - text: 'Bye.',
655 - },
656 - ],
657 - };
658 -
659 - assertTreeMatches([
660 - [elementBefore, treeBefore],
661 - [elementAfter, treeAfter],
662 - ]);
663 - });
664 -
665 - it('updates from no children to a single text child', () => {
666 - var elementBefore = <div />;
667 - var treeBefore = {
668 - displayName: 'div',
669 - children: [],
670 - };
671 -
672 - var elementAfter = <div>Hi.</div>;
673 - var treeAfter = {
674 - displayName: 'div',
675 - children: [
676 - {
677 - displayName: '#text',
678 - text: 'Hi.',
679 - },
680 - ],
681 - };
682 -
683 - assertTreeMatches([
684 - [elementBefore, treeBefore],
685 - [elementAfter, treeAfter],
686 - ]);
687 - });
688 -
689 - it('updates from a single text child to no children', () => {
690 - var elementBefore = <div>Hi.</div>;
691 - var treeBefore = {
692 - displayName: 'div',
693 - children: [
694 - {
695 - displayName: '#text',
696 - text: 'Hi.',
697 - },
698 - ],
699 - };
700 -
701 - var elementAfter = <div />;
702 - var treeAfter = {
703 - displayName: 'div',
704 - children: [],
705 - };
706 -
707 - assertTreeMatches([
708 - [elementBefore, treeBefore],
709 - [elementAfter, treeAfter],
710 - ]);
711 - });
712 -
713 - it('updates from html content to a single text child', () => {
714 - var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
715 - var treeBefore = {
716 - displayName: 'div',
717 - children: [],
718 - };
719 -
720 - var elementAfter = <div>Hi.</div>;
721 - var treeAfter = {
722 - displayName: 'div',
723 - children: [
724 - {
725 - displayName: '#text',
726 - text: 'Hi.',
727 - },
728 - ],
729 - };
730 -
731 - assertTreeMatches([
732 - [elementBefore, treeBefore],
733 - [elementAfter, treeAfter],
734 - ]);
735 - });
736 -
737 - it('updates from a single text child to html content', () => {
738 - var elementBefore = <div>Hi.</div>;
739 - var treeBefore = {
740 - displayName: 'div',
741 - children: [
742 - {
743 - displayName: '#text',
744 - text: 'Hi.',
745 - },
746 - ],
747 - };
748 -
749 - var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
750 - var treeAfter = {
751 - displayName: 'div',
752 - children: [],
753 - };
754 -
755 - assertTreeMatches([
756 - [elementBefore, treeBefore],
757 - [elementAfter, treeAfter],
758 - ]);
759 - });
760 -
761 - it('updates from no children to multiple text children', () => {
762 - var elementBefore = <div />;
763 - var treeBefore = {
764 - displayName: 'div',
765 - children: [],
766 - };
767 -
768 - var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
769 - var treeAfter = {
770 - displayName: 'div',
771 - children: [
772 - {
773 - displayName: '#text',
774 - text: 'Hi.',
775 - },
776 - {
777 - displayName: '#text',
778 - text: 'Bye.',
779 - },
780 - ],
781 - };
782 -
783 - assertTreeMatches([
784 - [elementBefore, treeBefore],
785 - [elementAfter, treeAfter],
786 - ]);
787 - });
788 -
789 - it('updates from multiple text children to no children', () => {
790 - var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
791 - var treeBefore = {
792 - displayName: 'div',
793 - children: [
794 - {
795 - displayName: '#text',
796 - text: 'Hi.',
797 - },
798 - {
799 - displayName: '#text',
800 - text: 'Bye.',
801 - },
802 - ],
803 - };
804 -
805 - var elementAfter = <div />;
806 - var treeAfter = {
807 - displayName: 'div',
808 - children: [],
809 - };
810 -
811 - assertTreeMatches([
812 - [elementBefore, treeBefore],
813 - [elementAfter, treeAfter],
814 - ]);
815 - });
816 -
817 - it('updates from html content to multiple text children', () => {
818 - var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
819 - var treeBefore = {
820 - displayName: 'div',
821 - children: [],
822 - };
823 -
824 - var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
825 - var treeAfter = {
826 - displayName: 'div',
827 - children: [
828 - {
829 - displayName: '#text',
830 - text: 'Hi.',
831 - },
832 - {
833 - displayName: '#text',
834 - text: 'Bye.',
835 - },
836 - ],
837 - };
838 -
839 - assertTreeMatches([
840 - [elementBefore, treeBefore],
841 - [elementAfter, treeAfter],
842 - ]);
843 - });
844 -
845 - it('updates from multiple text children to html content', () => {
846 - var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
847 - var treeBefore = {
848 - displayName: 'div',
849 - children: [
850 - {
851 - displayName: '#text',
852 - text: 'Hi.',
853 - },
854 - {
855 - displayName: '#text',
856 - text: 'Bye.',
857 - },
858 - ],
859 - };
860 -
861 - var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
862 - var treeAfter = {
863 - displayName: 'div',
864 - children: [],
865 - };
866 -
867 - assertTreeMatches([
868 - [elementBefore, treeBefore],
869 - [elementAfter, treeAfter],
870 - ]);
871 - });
872 -
873 - it('updates from html content to no children', () => {
874 - var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
875 - var treeBefore = {
876 - displayName: 'div',
877 - children: [],
878 - };
879 -
880 - var elementAfter = <div />;
881 - var treeAfter = {
882 - displayName: 'div',
883 - children: [],
884 - };
885 -
886 - assertTreeMatches([
887 - [elementBefore, treeBefore],
888 - [elementAfter, treeAfter],
889 - ]);
890 - });
891 -
892 - it('updates from no children to html content', () => {
893 - var elementBefore = <div />;
894 - var treeBefore = {
895 - displayName: 'div',
896 - children: [],
897 - };
898 -
899 - var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
900 - var treeAfter = {
901 - displayName: 'div',
902 - children: [],
903 - };
904 -
905 - assertTreeMatches([
906 - [elementBefore, treeBefore],
907 - [elementAfter, treeAfter],
908 - ]);
909 - });
910 -
911 - it('updates from one text child to multiple text children', () => {
912 - var elementBefore = <div>Hi.</div>;
913 - var treeBefore = {
914 - displayName: 'div',
915 - children: [
916 - {
917 - displayName: '#text',
918 - text: 'Hi.',
919 - },
920 - ],
921 - };
922 -
923 - var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
924 - var treeAfter = {
925 - displayName: 'div',
926 - children: [
927 - {
928 - displayName: '#text',
929 - text: 'Hi.',
930 - },
931 - {
932 - displayName: '#text',
933 - text: 'Bye.',
934 - },
935 - ],
936 - };
937 -
938 - assertTreeMatches([
939 - [elementBefore, treeBefore],
940 - [elementAfter, treeAfter],
941 - ]);
942 - });
943 -
944 - it('updates from multiple text children to one text child', () => {
945 - var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
946 - var treeBefore = {
947 - displayName: 'div',
948 - children: [
949 - {
950 - displayName: '#text',
951 - text: 'Hi.',
952 - },
953 - {
954 - displayName: '#text',
955 - text: 'Bye.',
956 - },
957 - ],
958 - };
959 -
960 - var elementAfter = <div>Hi.</div>;
961 - var treeAfter = {
962 - displayName: 'div',
963 - children: [
964 - {
965 - displayName: '#text',
966 - text: 'Hi.',
967 - },
968 - ],
969 - };
970 - assertTreeMatches([
971 - [elementBefore, treeBefore],
972 - [elementAfter, treeAfter],
973 - ]);
974 - });
975 -
976 - it('updates text nodes when reordering', () => {
977 - var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
978 - var treeBefore = {
979 - displayName: 'div',
980 - children: [
981 - {
982 - displayName: '#text',
983 - text: 'Hi.',
984 - },
985 - {
986 - displayName: '#text',
987 - text: 'Bye.',
988 - },
989 - ],
990 - };
991 -
992 - var elementAfter = <div>{'Bye.'}{'Hi.'}</div>;
993 - var treeAfter = {
994 - displayName: 'div',
995 - children: [
996 - {
997 - displayName: '#text',
998 - text: 'Bye.',
999 - },
1000 - {
1001 - displayName: '#text',
1002 - text: 'Hi.',
1003 - },
1004 - ],
1005 - };
1006 - assertTreeMatches([
1007 - [elementBefore, treeBefore],
1008 - [elementAfter, treeAfter],
1009 - ]);
1010 - });
1011 -
1012 - it('updates host nodes when reordering with keys', () => {
1013 - var elementBefore = (
1014 - <div>
1015 - <div key="a">Hi.</div>
1016 - <div key="b">Bye.</div>
1017 - </div>
1018 - );
1019 - var treeBefore = {
1020 - displayName: 'div',
1021 - children: [
1022 - {
1023 - displayName: 'div',
1024 - children: [
1025 - {
1026 - displayName: '#text',
1027 - text: 'Hi.',
1028 - },
1029 - ],
1030 - },
1031 - {
1032 - displayName: 'div',
1033 - children: [
1034 - {
1035 - displayName: '#text',
1036 - text: 'Bye.',
1037 - },
1038 - ],
1039 - },
1040 - ],
1041 - };
1042 -
1043 - var elementAfter = (
1044 - <div>
1045 - <div key="b">Bye.</div>
1046 - <div key="a">Hi.</div>
1047 - </div>
1048 - );
1049 - var treeAfter = {
1050 - displayName: 'div',
1051 - children: [
1052 - {
1053 - displayName: 'div',
1054 - children: [
1055 - {
1056 - displayName: '#text',
1057 - text: 'Bye.',
1058 - },
1059 - ],
1060 - },
1061 - {
1062 - displayName: 'div',
1063 - children: [
1064 - {
1065 - displayName: '#text',
1066 - text: 'Hi.',
1067 - },
1068 - ],
1069 - },
1070 - ],
1071 - };
1072 -
1073 - assertTreeMatches([
1074 - [elementBefore, treeBefore],
1075 - [elementAfter, treeAfter],
1076 - ]);
1077 - });
1078 -
1079 - it('updates host nodes when reordering without keys', () => {
1080 - var elementBefore = (
1081 - <div>
1082 - <div>Hi.</div>
1083 - <div>Bye.</div>
1084 - </div>
1085 - );
1086 - var treeBefore = {
1087 - displayName: 'div',
1088 - children: [
1089 - {
1090 - displayName: 'div',
1091 - children: [
1092 - {
1093 - displayName: '#text',
1094 - text: 'Hi.',
1095 - },
1096 - ],
1097 - },
1098 - {
1099 - displayName: 'div',
1100 - children: [
1101 - {
1102 - displayName: '#text',
1103 - text: 'Bye.',
1104 - },
1105 - ],
1106 - },
1107 - ],
1108 - };
1109 -
1110 - var elementAfter = (
1111 - <div>
1112 - <div>Bye.</div>
1113 - <div>Hi.</div>
1114 - </div>
1115 - );
1116 - var treeAfter = {
1117 - displayName: 'div',
1118 - children: [
1119 - {
1120 - displayName: 'div',
1121 - children: [
1122 - {
1123 - displayName: '#text',
1124 - text: 'Bye.',
1125 - },
1126 - ],
1127 - },
1128 - {
1129 - displayName: 'div',
1130 - children: [
1131 - {
1132 - displayName: '#text',
1133 - text: 'Hi.',
1134 - },
1135 - ],
1136 - },
1137 - ],
1138 - };
1139 -
1140 - assertTreeMatches([
1141 - [elementBefore, treeBefore],
1142 - [elementAfter, treeAfter],
1143 - ]);
1144 - });
1145 -
1146 - it('updates a single composite child of a different type', () => {
1147 - function Foo() {
1148 - return null;
1149 - }
1150 -
1151 - function Bar() {
1152 - return null;
1153 - }
1154 -
1155 - var elementBefore = <div><Foo /></div>;
1156 - var treeBefore = {
1157 - displayName: 'div',
1158 - children: [
1159 - {
1160 - displayName: 'Foo',
1161 - children: [],
1162 - },
1163 - ],
1164 - };
1165 -
1166 - var elementAfter = <div><Bar /></div>;
1167 - var treeAfter = {
1168 - displayName: 'div',
1169 - children: [
1170 - {
1171 - displayName: 'Bar',
1172 - children: [],
1173 - },
1174 - ],
1175 - };
1176 -
1177 - assertTreeMatches([
1178 - [elementBefore, treeBefore],
1179 - [elementAfter, treeAfter],
1180 - ]);
1181 - });
1182 -
1183 - it('updates a single composite child of the same type', () => {
1184 - function Foo({children}) {
1185 - return children;
1186 - }
1187 -
1188 - var elementBefore = <div><Foo><div /></Foo></div>;
1189 - var treeBefore = {
1190 - displayName: 'div',
1191 - children: [
1192 - {
1193 - displayName: 'Foo',
1194 - children: [
1195 - {
1196 - displayName: 'div',
1197 - children: [],
1198 - },
1199 - ],
1200 - },
1201 - ],
1202 - };
1203 -
1204 - var elementAfter = <div><Foo><span /></Foo></div>;
1205 - var treeAfter = {
1206 - displayName: 'div',
1207 - children: [
1208 - {
1209 - displayName: 'Foo',
1210 - children: [
1211 - {
1212 - displayName: 'span',
1213 - children: [],
1214 - },
1215 - ],
1216 - },
1217 - ],
1218 - };
1219 -
1220 - assertTreeMatches([
1221 - [elementBefore, treeBefore],
1222 - [elementAfter, treeAfter],
1223 - ]);
1224 - });
1225 -
1226 - it('updates from no children to a single composite child', () => {
1227 - function Foo() {
1228 - return null;
1229 - }
1230 -
1231 - var elementBefore = <div />;
1232 - var treeBefore = {
1233 - displayName: 'div',
1234 - children: [],
1235 - };
1236 -
1237 - var elementAfter = <div><Foo /></div>;
1238 - var treeAfter = {
1239 - displayName: 'div',
1240 - children: [
1241 - {
1242 - displayName: 'Foo',
1243 - children: [],
1244 - },
1245 - ],
1246 - };
1247 -
1248 - assertTreeMatches([
1249 - [elementBefore, treeBefore],
1250 - [elementAfter, treeAfter],
1251 - ]);
1252 - });
1253 -
1254 - it('updates from a single composite child to no children', () => {
1255 - function Foo() {
1256 - return null;
1257 - }
1258 -
1259 - var elementBefore = <div><Foo /></div>;
1260 - var treeBefore = {
1261 - displayName: 'div',
1262 - children: [
1263 - {
1264 - displayName: 'Foo',
1265 - children: [],
1266 - },
1267 - ],
1268 - };
1269 -
1270 - var elementAfter = <div />;
1271 - var treeAfter = {
1272 - displayName: 'div',
1273 - children: [],
1274 - };
1275 -
1276 - assertTreeMatches([
1277 - [elementBefore, treeBefore],
1278 - [elementAfter, treeAfter],
1279 - ]);
1280 - });
1281 -
1282 - it('updates mixed children', () => {
1283 - function Foo() {
1284 - return <div />;
1285 - }
1286 - var element1 = (
1287 - <div>
1288 - {'hi'}
1289 - {false}
1290 - {42}
1291 - {null}
1292 - <Foo />
1293 - </div>
1294 - );
1295 - var tree1 = {
1296 - displayName: 'div',
1297 - children: [
1298 - {
1299 - displayName: '#text',
1300 - text: 'hi',
1301 - },
1302 - {
1303 - displayName: '#text',
1304 - text: '42',
1305 - },
1306 - {
1307 - displayName: 'Foo',
1308 - children: [
1309 - {
1310 - displayName: 'div',
1311 - children: [],
1312 - },
1313 - ],
1314 - },
1315 - ],
1316 - };
1317 -
1318 - var element2 = (
1319 - <div>
1320 - <Foo />
1321 - {false}
1322 - {'hi'}
1323 - {null}
1324 - </div>
1325 - );
1326 - var tree2 = {
1327 - displayName: 'div',
1328 - children: [
1329 - {
1330 - displayName: 'Foo',
1331 - children: [
1332 - {
1333 - displayName: 'div',
1334 - children: [],
1335 - },
1336 - ],
1337 - },
1338 - {
1339 - displayName: '#text',
1340 - text: 'hi',
1341 - },
1342 - ],
1343 - };
1344 -
1345 - var element3 = (
1346 - <div>
1347 - <Foo />
1348 - </div>
1349 - );
1350 - var tree3 = {
1351 - displayName: 'div',
1352 - children: [
1353 - {
1354 - displayName: 'Foo',
1355 - children: [
1356 - {
1357 - displayName: 'div',
1358 - children: [],
1359 - },
1360 - ],
1361 - },
1362 - ],
1363 - };
1364 -
1365 - assertTreeMatches([
1366 - [element1, tree1],
1367 - [element2, tree2],
1368 - [element3, tree3],
1369 - ]);
1370 - });
1371 - });
1372 -
1373 - describe('functional component', () => {
1374 - it('updates with a host child', () => {
1375 - function Foo({children}) {
1376 - return children;
1377 - }
1378 -
1379 - var elementBefore = <Foo><div /></Foo>;
1380 - var treeBefore = {
1381 - displayName: 'Foo',
1382 - children: [
1383 - {
1384 - displayName: 'div',
1385 - children: [],
1386 - },
1387 - ],
1388 - };
1389 -
1390 - var elementAfter = <Foo><span /></Foo>;
1391 - var treeAfter = {
1392 - displayName: 'Foo',
1393 - children: [
1394 - {
1395 - displayName: 'span',
1396 - children: [],
1397 - },
1398 - ],
1399 - };
1400 -
1401 - assertTreeMatches([
1402 - [elementBefore, treeBefore],
1403 - [elementAfter, treeAfter],
1404 - ]);
1405 - });
1406 -
1407 - it('updates from null to a host child', () => {
1408 - function Foo({children}) {
1409 - return children;
1410 - }
1411 -
1412 - var elementBefore = <Foo>{null}</Foo>;
1413 - var treeBefore = {
1414 - displayName: 'Foo',
1415 - children: [],
1416 - };
1417 -
1418 - var elementAfter = <Foo><div /></Foo>;
1419 - var treeAfter = {
1420 - displayName: 'Foo',
1421 - children: [
1422 - {
1423 - displayName: 'div',
1424 - children: [],
1425 - },
1426 - ],
1427 - };
1428 -
1429 - assertTreeMatches([
1430 - [elementBefore, treeBefore],
1431 - [elementAfter, treeAfter],
1432 - ]);
1433 - });
1434 -
1435 - it('updates from a host child to null', () => {
1436 - function Foo({children}) {
1437 - return children;
1438 - }
1439 -
1440 - var elementBefore = <Foo><div /></Foo>;
1441 - var treeBefore = {
1442 - displayName: 'Foo',
1443 - children: [
1444 - {
1445 - displayName: 'div',
1446 - children: [],
1447 - },
1448 - ],
1449 - };
1450 -
1451 - var elementAfter = <Foo>{null}</Foo>;
1452 - var treeAfter = {
1453 - displayName: 'Foo',
1454 - children: [],
1455 - };
1456 -
1457 - assertTreeMatches([
1458 - [elementBefore, treeBefore],
1459 - [elementAfter, treeAfter],
1460 - ]);
1461 - });
1462 -
1463 - it('updates from a host child to a composite child', () => {
1464 - function Bar() {
1465 - return null;
1466 - }
1467 -
1468 - function Foo({children}) {
1469 - return children;
1470 - }
1471 -
1472 - var elementBefore = <Foo><div /></Foo>;
1473 - var treeBefore = {
1474 - displayName: 'Foo',
1475 - children: [
1476 - {
1477 - displayName: 'div',
1478 - children: [],
1479 - },
1480 - ],
1481 - };
1482 -
1483 - var elementAfter = <Foo><Bar /></Foo>;
1484 - var treeAfter = {
1485 - displayName: 'Foo',
1486 - children: [
1487 - {
1488 - displayName: 'Bar',
1489 - children: [],
1490 - },
1491 - ],
1492 - };
1493 -
1494 - assertTreeMatches([
1495 - [elementBefore, treeBefore],
1496 - [elementAfter, treeAfter],
1497 - ]);
1498 - });
1499 -
1500 - it('updates from a composite child to a host child', () => {
1501 - function Bar() {
1502 - return null;
1503 - }
1504 -
1505 - function Foo({children}) {
1506 - return children;
1507 - }
1508 -
1509 - var elementBefore = <Foo><Bar /></Foo>;
1510 - var treeBefore = {
1511 - displayName: 'Foo',
1512 - children: [
1513 - {
1514 - displayName: 'Bar',
1515 - children: [],
1516 - },
1517 - ],
1518 - };
1519 -
1520 - var elementAfter = <Foo><div /></Foo>;
1521 - var treeAfter = {
1522 - displayName: 'Foo',
1523 - children: [
1524 - {
1525 - displayName: 'div',
1526 - children: [],
1527 - },
1528 - ],
1529 - };
1530 -
1531 - assertTreeMatches([
1532 - [elementBefore, treeBefore],
1533 - [elementAfter, treeAfter],
1534 - ]);
1535 - });
1536 -
1537 - it('updates from null to a composite child', () => {
1538 - function Bar() {
1539 - return null;
1540 - }
1541 -
1542 - function Foo({children}) {
1543 - return children;
1544 - }
1545 -
1546 - var elementBefore = <Foo>{null}</Foo>;
1547 - var treeBefore = {
1548 - displayName: 'Foo',
1549 - children: [],
1550 - };
1551 -
1552 - var elementAfter = <Foo><Bar /></Foo>;
1553 - var treeAfter = {
1554 - displayName: 'Foo',
1555 - children: [
1556 - {
1557 - displayName: 'Bar',
1558 - children: [],
1559 - },
1560 - ],
1561 - };
1562 -
1563 - assertTreeMatches([
1564 - [elementBefore, treeBefore],
1565 - [elementAfter, treeAfter],
1566 - ]);
1567 - });
1568 -
1569 - it('updates from a composite child to null', () => {
1570 - function Bar() {
1571 - return null;
1572 - }
1573 -
1574 - function Foo({children}) {
1575 - return children;
1576 - }
1577 -
1578 - var elementBefore = <Foo><Bar /></Foo>;
1579 - var treeBefore = {
1580 - displayName: 'Foo',
1581 - children: [
1582 - {
1583 - displayName: 'Bar',
1584 - children: [],
1585 - },
1586 - ],
1587 - };
1588 -
1589 - var elementAfter = <Foo>{null}</Foo>;
1590 - var treeAfter = {
1591 - displayName: 'Foo',
1592 - children: [],
1593 - };
1594 -
1595 - assertTreeMatches([
1596 - [elementBefore, treeBefore],
1597 - [elementAfter, treeAfter],
1598 - ]);
1599 - });
1600 - });
1601 -
1602 - describe('class component', () => {
1603 - it('updates with a host child', () => {
1604 - class Foo extends React.Component {
1605 - render() {
1606 - return this.props.children;
1607 - }
1608 - }
1609 -
1610 - var elementBefore = <Foo><div /></Foo>;
1611 - var treeBefore = {
1612 - displayName: 'Foo',
1613 - children: [
1614 - {
1615 - displayName: 'div',
1616 - children: [],
1617 - },
1618 - ],
1619 - };
1620 -
1621 - var elementAfter = <Foo><span /></Foo>;
1622 - var treeAfter = {
1623 - displayName: 'Foo',
1624 - children: [
1625 - {
1626 - displayName: 'span',
1627 - children: [],
1628 - },
1629 - ],
1630 - };
1631 -
1632 - assertTreeMatches([
1633 - [elementBefore, treeBefore],
1634 - [elementAfter, treeAfter],
1635 - ]);
1636 - });
1637 -
1638 - it('updates from null to a host child', () => {
1639 - class Foo extends React.Component {
1640 - render() {
1641 - return this.props.children;
1642 - }
1643 - }
1644 -
1645 - var elementBefore = <Foo>{null}</Foo>;
1646 - var treeBefore = {
1647 - displayName: 'Foo',
1648 - children: [],
1649 - };
1650 -
1651 - var elementAfter = <Foo><div /></Foo>;
1652 - var treeAfter = {
1653 - displayName: 'Foo',
1654 - children: [
1655 - {
1656 - displayName: 'div',
1657 - children: [],
1658 - },
1659 - ],
1660 - };
1661 -
1662 - assertTreeMatches([
1663 - [elementBefore, treeBefore],
1664 - [elementAfter, treeAfter],
1665 - ]);
1666 - });
1667 -
1668 - it('updates from a host child to null', () => {
1669 - class Foo extends React.Component {
1670 - render() {
1671 - return this.props.children;
1672 - }
1673 - }
1674 -
1675 - var elementBefore = <Foo><div /></Foo>;
1676 - var treeBefore = {
1677 - displayName: 'Foo',
1678 - children: [
1679 - {
1680 - displayName: 'div',
1681 - children: [],
1682 - },
1683 - ],
1684 - };
1685 -
1686 - var elementAfter = <Foo>{null}</Foo>;
1687 - var treeAfter = {
1688 - displayName: 'Foo',
1689 - children: [],
1690 - };
1691 -
1692 - assertTreeMatches([
1693 - [elementBefore, treeBefore],
1694 - [elementAfter, treeAfter],
1695 - ]);
1696 - });
1697 -
1698 - it('updates from a host child to a composite child', () => {
1699 - class Bar extends React.Component {
1700 - render() {
1701 - return null;
1702 - }
1703 - }
1704 -
1705 - class Foo extends React.Component {
1706 - render() {
1707 - return this.props.children;
1708 - }
1709 - }
1710 -
1711 - var elementBefore = <Foo><div /></Foo>;
1712 - var treeBefore = {
1713 - displayName: 'Foo',
1714 - children: [
1715 - {
1716 - displayName: 'div',
1717 - children: [],
1718 - },
1719 - ],
1720 - };
1721 -
1722 - var elementAfter = <Foo><Bar /></Foo>;
1723 - var treeAfter = {
1724 - displayName: 'Foo',
1725 - children: [
1726 - {
1727 - displayName: 'Bar',
1728 - children: [],
1729 - },
1730 - ],
1731 - };
1732 -
1733 - assertTreeMatches([
1734 - [elementBefore, treeBefore],
1735 - [elementAfter, treeAfter],
1736 - ]);
1737 - });
1738 -
1739 - it('updates from a composite child to a host child', () => {
1740 - class Bar extends React.Component {
1741 - render() {
1742 - return null;
1743 - }
1744 - }
1745 -
1746 - class Foo extends React.Component {
1747 - render() {
1748 - return this.props.children;
1749 - }
1750 - }
1751 -
1752 - var elementBefore = <Foo><Bar /></Foo>;
1753 - var treeBefore = {
1754 - displayName: 'Foo',
1755 - children: [
1756 - {
1757 - displayName: 'Bar',
1758 - children: [],
1759 - },
1760 - ],
1761 - };
1762 -
1763 - var elementAfter = <Foo><div /></Foo>;
1764 - var treeAfter = {
1765 - displayName: 'Foo',
1766 - children: [
1767 - {
1768 - displayName: 'div',
1769 - children: [],
1770 - },
1771 - ],
1772 - };
1773 -
1774 - assertTreeMatches([
1775 - [elementBefore, treeBefore],
1776 - [elementAfter, treeAfter],
1777 - ]);
1778 - });
1779 -
1780 - it('updates from null to a composite child', () => {
1781 - class Bar extends React.Component {
1782 - render() {
1783 - return null;
1784 - }
1785 - }
1786 -
1787 - class Foo extends React.Component {
1788 - render() {
1789 - return this.props.children;
1790 - }
1791 - }
1792 -
1793 - var elementBefore = <Foo>{null}</Foo>;
1794 - var treeBefore = {
1795 - displayName: 'Foo',
1796 - children: [],
1797 - };
1798 -
1799 - var elementAfter = <Foo><Bar /></Foo>;
1800 - var treeAfter = {
1801 - displayName: 'Foo',
1802 - children: [
1803 - {
1804 - displayName: 'Bar',
1805 - children: [],
1806 - },
1807 - ],
1808 - };
1809 -
1810 - assertTreeMatches([
1811 - [elementBefore, treeBefore],
1812 - [elementAfter, treeAfter],
1813 - ]);
1814 - });
1815 -
1816 - it('updates from a composite child to null', () => {
1817 - class Bar extends React.Component {
1818 - render() {
1819 - return null;
1820 - }
1821 - }
1822 -
1823 - class Foo extends React.Component {
1824 - render() {
1825 - return this.props.children;
1826 - }
1827 - }
1828 -
1829 - var elementBefore = <Foo><Bar /></Foo>;
1830 - var treeBefore = {
1831 - displayName: 'Foo',
1832 - children: [
1833 - {
1834 - displayName: 'Bar',
1835 - children: [],
1836 - },
1837 - ],
1838 - };
1839 -
1840 - var elementAfter = <Foo>{null}</Foo>;
1841 - var treeAfter = {
1842 - displayName: 'Foo',
1843 - children: [],
1844 - };
1845 -
1846 - assertTreeMatches([
1847 - [elementBefore, treeBefore],
1848 - [elementAfter, treeAfter],
1849 - ]);
1850 - });
1851 - });
1852 - });
1853 -
1854 - describe('misc', () => {
1855 - it('tracks owner correctly', () => {
1856 - class Foo extends React.Component {
1857 - render() {
1858 - return <Bar><h1>Hi.</h1></Bar>;
1859 - }
1860 - }
1861 - function Bar({children}) {
1862 - return <div>{children} Mom</div>;
1863 - }
1864 -
1865 - // Note that owner is not calculated for text nodes
1866 - // because they are not created from real elements.
1867 - var element = <article><Foo /></article>;
1868 - var tree = {
1869 - displayName: 'article',
1870 - children: [
1871 - {
1872 - displayName: 'Foo',
1873 - children: [
1874 - {
1875 - displayName: 'Bar',
1876 - ownerDisplayName: 'Foo',
1877 - children: [
1878 - {
1879 - displayName: 'div',
1880 - ownerDisplayName: 'Bar',
1881 - children: [
1882 - {
1883 - displayName: 'h1',
1884 - ownerDisplayName: 'Foo',
1885 - children: [
1886 - {
1887 - displayName: '#text',
1888 - text: 'Hi.',
1889 - },
1890 - ],
1891 - },
1892 - {
1893 - displayName: '#text',
1894 - text: ' Mom',
1895 - },
1896 - ],
1897 - },
1898 - ],
1899 - },
1900 - ],
1901 - },
1902 - ],
1903 - };
1904 - assertTreeMatches([element, tree]);
1905 - });
1906 -
1907 - it('purges unmounted components automatically', () => {
1908 - var node = document.createElement('div');
1909 - var renderBar = true;
1910 - var fooInstance;
1911 - var barInstance;
1912 -
1913 - class Foo extends React.Component {
1914 - render() {
1915 - fooInstance = ReactInstanceMap.get(this);
1916 - return renderBar ? <Bar /> : null;
1917 - }
1918 - }
1919 -
1920 - class Bar extends React.Component {
1921 - render() {
1922 - barInstance = ReactInstanceMap.get(this);
1923 - return null;
1924 - }
1925 - }
1926 -
1927 - ReactDOM.render(<Foo />, node);
1928 - ReactComponentTreeTestUtils.expectTree(
1929 - barInstance._debugID,
1930 - {
1931 - displayName: 'Bar',
1932 - parentDisplayName: 'Foo',
1933 - parentID: fooInstance._debugID,
1934 - children: [],
1935 - },
1936 - 'Foo',
1937 - );
1938 -
1939 - renderBar = false;
1940 - ReactDOM.render(<Foo />, node);
1941 - ReactDOM.render(<Foo />, node);
1942 - ReactComponentTreeTestUtils.expectTree(
1943 - barInstance._debugID,
1944 - {
1945 - displayName: 'Unknown',
1946 - children: [],
1947 - parentID: null,
1948 - },
1949 - 'Foo',
1950 - );
1951 -
1952 - ReactDOM.unmountComponentAtNode(node);
1953 - ReactComponentTreeTestUtils.expectTree(
1954 - barInstance._debugID,
1955 - {
1956 - displayName: 'Unknown',
1957 - children: [],
1958 - parentID: null,
1959 - },
1960 - 'Foo',
1961 - );
1962 - });
1963 -
1964 - it('reports update counts', () => {
1965 - var node = document.createElement('div');
1966 -
1967 - ReactDOM.render(<div className="a" />, node);
1968 - var divID = ReactComponentTreeHook.getRootIDs()[0];
1969 - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
1970 -
1971 - ReactDOM.render(<span className="a" />, node);
1972 - var spanID = ReactComponentTreeHook.getRootIDs()[0];
1973 - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
1974 - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0);
1975 -
1976 - ReactDOM.render(<span className="b" />, node);
1977 - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
1978 - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(1);
1979 -
1980 - ReactDOM.render(<span className="c" />, node);
1981 - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
1982 - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(2);
1983 -
1984 - ReactDOM.unmountComponentAtNode(node);
1985 - expectDev(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
1986 - expectDev(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0);
1987 - });
1988 -
1989 - it('does not report top-level wrapper as a root', () => {
1990 - var node = document.createElement('div');
1991 -
1992 - ReactDOM.render(<div className="a" />, node);
1993 - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([
1994 - 'div',
1995 - ]);
1996 -
1997 - ReactDOM.render(<div className="b" />, node);
1998 - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([
1999 - 'div',
2000 - ]);
2001 -
2002 - ReactDOM.unmountComponentAtNode(node);
2003 - expectDev(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([]);
2004 - expectDev(
2005 - ReactComponentTreeTestUtils.getRegisteredDisplayNames(),
2006 - ).toEqual([]);
2007 - });
2008 -
2009 - it('registers inlined text nodes', () => {
2010 - var node = document.createElement('div');
2011 -
2012 - ReactDOM.render(<div>hi</div>, node);
2013 - expectDev(
2014 - ReactComponentTreeTestUtils.getRegisteredDisplayNames(),
2015 - ).toEqual(['div', '#text']);
2016 -
2017 - ReactDOM.unmountComponentAtNode(node);
2018 - expectDev(
2019 - ReactComponentTreeTestUtils.getRegisteredDisplayNames(),
2020 - ).toEqual([]);
2021 - });
2022 - });
2023 -
2024 - describe('in environment without Map, Set and Array.from', () => {
2025 - var realMap;
2026 - var realSet;
2027 - var realArrayFrom;
2028 -
2029 - beforeEach(() => {
2030 - realMap = global.Map;
2031 - realSet = global.Set;
2032 - realArrayFrom = Array.from;
2033 -
2034 - global.Map = undefined;
2035 - global.Set = undefined;
2036 - Array.from = undefined;
2037 -
2038 - jest.resetModules();
2039 -
2040 - React = require('react');
2041 - ReactDOM = require('react-dom');
2042 - ReactInstanceMap = require('ReactInstanceMap');
2043 - ReactComponentTreeHook = require('ReactComponentTreeHook');
2044 - ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
2045 - });
2046 -
2047 - afterEach(() => {
2048 - global.Map = realMap;
2049 - global.Set = realSet;
2050 - Array.from = realArrayFrom;
2051 - });
2052 -
2053 - it('works', () => {
2054 - class Qux extends React.Component {
2055 - render() {
2056 - return null;
2057 - }
2058 - }
2059 -
2060 - function Foo() {
2061 - return {
2062 - render() {
2063 - return <Qux />;
2064 - },
2065 - };
2066 - }
2067 - function Bar({children}) {
2068 - return <h1>{children}</h1>;
2069 - }
2070 - class Baz extends React.Component {
2071 - render() {
2072 - return (
2073 - <div>
2074 - <Foo />
2075 - <Bar>
2076 - <span>Hi,</span>
2077 - Mom
2078 - </Bar>
2079 - <a href="#">Click me.</a>
2080 - </div>
2081 - );
2082 - }
2083 - }
2084 -
2085 - var element = <Baz />;
2086 - var tree = {
2087 - displayName: 'Baz',
2088 - element,
2089 - children: [
2090 - {
2091 - displayName: 'div',
2092 - children: [
2093 - {
2094 - displayName: 'Foo',
2095 - element: <Foo />,
2096 - children: [
2097 - {
2098 - displayName: 'Qux',
2099 - element: <Qux />,
2100 - children: [],
2101 - },
2102 - ],
2103 - },
2104 - {
2105 - displayName: 'Bar',
2106 - children: [
2107 - {
2108 - displayName: 'h1',
2109 - children: [
2110 - {
2111 - displayName: 'span',
2112 - children: [
2113 - {
2114 - displayName: '#text',
2115 - element: 'Hi,',
2116 - text: 'Hi,',
2117 - },
2118 - ],
2119 - },
2120 - {
2121 - displayName: '#text',
2122 - text: 'Mom',
2123 - element: 'Mom',
2124 - },
2125 - ],
2126 - },
2127 - ],
2128 - },
2129 - {
2130 - displayName: 'a',
2131 - children: [
2132 - {
2133 - displayName: '#text',
2134 - text: 'Click me.',
2135 - element: 'Click me.',
2136 - },
2137 - ],
2138 - },
2139 - ],
2140 - },
2141 - ],
2142 - };
2143 - assertTreeMatches([element, tree]);
2144 - });
2145 - });
2146 -});
src/renderers/__tests__/ReactHostOperationHistoryHook-test.js deleted
-776
@@ -1,776 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -// This is only used by ReactPerf which is currently not supported on Fiber.
13 -// Use browser timeline integration instead.
14 -describe.skip('ReactHostOperationHistoryHook', () => {
15 - var React;
16 - var ReactPerf;
17 - var ReactDOM;
18 - var ReactDOMComponentTree;
19 - var ReactHostOperationHistoryHook;
20 -
21 - beforeEach(() => {
22 - jest.resetModules();
23 -
24 - React = require('react');
25 - ReactPerf = require('ReactPerf');
26 - ReactDOM = require('react-dom');
27 - ReactDOMComponentTree = require('ReactDOMComponentTree');
28 - ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
29 -
30 - ReactPerf.start();
31 - });
32 -
33 - afterEach(() => {
34 - ReactPerf.stop();
35 - });
36 -
37 - function assertHistoryMatches(expectedHistory) {
38 - var actualHistory = ReactHostOperationHistoryHook.getHistory();
39 - expectDev(actualHistory).toEqual(expectedHistory);
40 - }
41 -
42 - describe('mount', () => {
43 - it('gets recorded for host roots', () => {
44 - var node = document.createElement('div');
45 - ReactHostOperationHistoryHook._preventClearing = true;
46 - ReactDOM.render(<div><p>Hi.</p></div>, node);
47 -
48 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
49 - assertHistoryMatches([
50 - {
51 - instanceID: inst._debugID,
52 - type: 'mount',
53 - payload: 'DIV',
54 - },
55 - ]);
56 - });
57 -
58 - it('gets recorded for composite roots', () => {
59 - function Foo() {
60 - return <div><p>Hi.</p></div>;
61 - }
62 - var node = document.createElement('div');
63 -
64 - ReactHostOperationHistoryHook._preventClearing = true;
65 - ReactDOM.render(<Foo />, node);
66 -
67 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
68 - assertHistoryMatches([
69 - {
70 - instanceID: inst._debugID,
71 - type: 'mount',
72 - payload: 'DIV',
73 - },
74 - ]);
75 - });
76 -
77 - it('gets ignored for composite roots that return null', () => {
78 - function Foo() {
79 - return null;
80 - }
81 - var node = document.createElement('div');
82 -
83 - ReactHostOperationHistoryHook._preventClearing = true;
84 - ReactDOM.render(<Foo />, node);
85 -
86 - // Empty DOM components should be invisible to hooks.
87 - assertHistoryMatches([]);
88 - });
89 -
90 - it('gets recorded when a native is mounted deeply instead of null', () => {
91 - var element;
92 - function Foo() {
93 - return element;
94 - }
95 -
96 - ReactHostOperationHistoryHook._preventClearing = true;
97 -
98 - var node = document.createElement('div');
99 - element = null;
100 - ReactDOM.render(<Foo />, node);
101 -
102 - element = <span />;
103 - ReactDOM.render(<Foo />, node);
104 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
105 -
106 - // Since empty components should be invisible to hooks,
107 - // we record a "mount" event rather than a "replace with".
108 - assertHistoryMatches([
109 - {
110 - instanceID: inst._debugID,
111 - type: 'mount',
112 - payload: 'SPAN',
113 - },
114 - ]);
115 - });
116 - });
117 -
118 - describe('update styles', () => {
119 - it('gets recorded during mount', () => {
120 - var node = document.createElement('div');
121 -
122 - ReactHostOperationHistoryHook._preventClearing = true;
123 - ReactDOM.render(
124 - <div
125 - style={{
126 - color: 'red',
127 - backgroundColor: 'yellow',
128 - }}
129 - />,
130 - node,
131 - );
132 -
133 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
134 - assertHistoryMatches([
135 - {
136 - instanceID: inst._debugID,
137 - type: 'update styles',
138 - payload: {
139 - color: 'red',
140 - backgroundColor: 'yellow',
141 - },
142 - },
143 - {
144 - instanceID: inst._debugID,
145 - type: 'mount',
146 - payload: 'DIV',
147 - },
148 - ]);
149 - });
150 -
151 - it('gets recorded during an update', () => {
152 - var node = document.createElement('div');
153 - ReactDOM.render(<div />, node);
154 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
155 -
156 - ReactHostOperationHistoryHook._preventClearing = true;
157 - ReactDOM.render(<div style={{color: 'red'}} />, node);
158 - ReactDOM.render(
159 - <div
160 - style={{
161 - color: 'blue',
162 - backgroundColor: 'yellow',
163 - }}
164 - />,
165 - node,
166 - );
167 - ReactDOM.render(<div style={{backgroundColor: 'green'}} />, node);
168 - ReactDOM.render(<div />, node);
169 -
170 - assertHistoryMatches([
171 - {
172 - instanceID: inst._debugID,
173 - type: 'update styles',
174 - payload: {color: 'red'},
175 - },
176 - {
177 - instanceID: inst._debugID,
178 - type: 'update styles',
179 - payload: {color: 'blue', backgroundColor: 'yellow'},
180 - },
181 - {
182 - instanceID: inst._debugID,
183 - type: 'update styles',
184 - payload: {color: '', backgroundColor: 'green'},
185 - },
186 - {
187 - instanceID: inst._debugID,
188 - type: 'update styles',
189 - payload: {backgroundColor: ''},
190 - },
191 - ]);
192 - });
193 -
194 - it('gets ignored if the styles are shallowly equal', () => {
195 - var node = document.createElement('div');
196 - ReactDOM.render(<div />, node);
197 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
198 -
199 - ReactHostOperationHistoryHook._preventClearing = true;
200 - ReactDOM.render(
201 - <div
202 - style={{
203 - color: 'red',
204 - backgroundColor: 'yellow',
205 - }}
206 - />,
207 - node,
208 - );
209 - ReactDOM.render(
210 - <div
211 - style={{
212 - color: 'red',
213 - backgroundColor: 'yellow',
214 - }}
215 - />,
216 - node,
217 - );
218 -
219 - assertHistoryMatches([
220 - {
221 - instanceID: inst._debugID,
222 - type: 'update styles',
223 - payload: {
224 - color: 'red',
225 - backgroundColor: 'yellow',
226 - },
227 - },
228 - ]);
229 - });
230 - });
231 -
232 - describe('update attribute', () => {
233 - describe('simple attribute', () => {
234 - it('gets recorded during mount', () => {
235 - var node = document.createElement('div');
236 -
237 - ReactHostOperationHistoryHook._preventClearing = true;
238 - ReactDOM.render(<div className="rad" tabIndex={42} />, node);
239 -
240 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
241 - assertHistoryMatches([
242 - {
243 - instanceID: inst._debugID,
244 - type: 'update attribute',
245 - payload: {className: 'rad'},
246 - },
247 - {
248 - instanceID: inst._debugID,
249 - type: 'update attribute',
250 - payload: {tabIndex: 42},
251 - },
252 - {
253 - instanceID: inst._debugID,
254 - type: 'mount',
255 - payload: 'DIV',
256 - },
257 - ]);
258 - });
259 -
260 - it('gets recorded during an update', () => {
261 - var node = document.createElement('div');
262 - ReactDOM.render(<div />, node);
263 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
264 -
265 - ReactHostOperationHistoryHook._preventClearing = true;
266 - ReactDOM.render(<div className="rad" />, node);
267 - ReactDOM.render(<div className="mad" tabIndex={42} />, node);
268 - ReactDOM.render(<div tabIndex={43} />, node);
269 -
270 - assertHistoryMatches([
271 - {
272 - instanceID: inst._debugID,
273 - type: 'update attribute',
274 - payload: {className: 'rad'},
275 - },
276 - {
277 - instanceID: inst._debugID,
278 - type: 'update attribute',
279 - payload: {className: 'mad'},
280 - },
281 - {
282 - instanceID: inst._debugID,
283 - type: 'update attribute',
284 - payload: {tabIndex: 42},
285 - },
286 - {
287 - instanceID: inst._debugID,
288 - type: 'remove attribute',
289 - payload: 'className',
290 - },
291 - {
292 - instanceID: inst._debugID,
293 - type: 'update attribute',
294 - payload: {tabIndex: 43},
295 - },
296 - ]);
297 - });
298 - });
299 -
300 - describe('attribute that gets removed with certain values', () => {
301 - it('gets recorded as a removal during an update', () => {
302 - var node = document.createElement('div');
303 - ReactDOM.render(<div />, node);
304 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
305 -
306 - ReactHostOperationHistoryHook._preventClearing = true;
307 - ReactDOM.render(<div disabled={true} />, node);
308 - ReactDOM.render(<div disabled={false} />, node);
309 -
310 - assertHistoryMatches([
311 - {
312 - instanceID: inst._debugID,
313 - type: 'update attribute',
314 - payload: {disabled: true},
315 - },
316 - {
317 - instanceID: inst._debugID,
318 - type: 'remove attribute',
319 - payload: 'disabled',
320 - },
321 - ]);
322 - });
323 - });
324 -
325 - describe('custom attribute', () => {
326 - it('gets recorded during mount', () => {
327 - var node = document.createElement('div');
328 -
329 - ReactHostOperationHistoryHook._preventClearing = true;
330 - ReactDOM.render(<div data-x="rad" data-y={42} />, node);
331 -
332 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
333 - assertHistoryMatches([
334 - {
335 - instanceID: inst._debugID,
336 - type: 'update attribute',
337 - payload: {'data-x': 'rad'},
338 - },
339 - {
340 - instanceID: inst._debugID,
341 - type: 'update attribute',
342 - payload: {'data-y': 42},
343 - },
344 - {
345 - instanceID: inst._debugID,
346 - type: 'mount',
347 - payload: 'DIV',
348 - },
349 - ]);
350 - });
351 -
352 - it('gets recorded during an update', () => {
353 - var node = document.createElement('div');
354 - ReactDOM.render(<div />, node);
355 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
356 -
357 - ReactHostOperationHistoryHook._preventClearing = true;
358 - ReactDOM.render(<div data-x="rad" />, node);
359 - ReactDOM.render(<div data-x="mad" data-y={42} />, node);
360 - ReactDOM.render(<div data-y={43} />, node);
361 -
362 - assertHistoryMatches([
363 - {
364 - instanceID: inst._debugID,
365 - type: 'update attribute',
366 - payload: {'data-x': 'rad'},
367 - },
368 - {
369 - instanceID: inst._debugID,
370 - type: 'update attribute',
371 - payload: {'data-x': 'mad'},
372 - },
373 - {
374 - instanceID: inst._debugID,
375 - type: 'update attribute',
376 - payload: {'data-y': 42},
377 - },
378 - {
379 - instanceID: inst._debugID,
380 - type: 'remove attribute',
381 - payload: 'data-x',
382 - },
383 - {
384 - instanceID: inst._debugID,
385 - type: 'update attribute',
386 - payload: {'data-y': 43},
387 - },
388 - ]);
389 - });
390 - });
391 -
392 - describe('attribute on a web component', () => {
393 - it('gets recorded during mount', () => {
394 - var node = document.createElement('div');
395 -
396 - ReactHostOperationHistoryHook._preventClearing = true;
397 - ReactDOM.render(<my-component className="rad" tabIndex={42} />, node);
398 -
399 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
400 - assertHistoryMatches([
401 - {
402 - instanceID: inst._debugID,
403 - type: 'update attribute',
404 - payload: {className: 'rad'},
405 - },
406 - {
407 - instanceID: inst._debugID,
408 - type: 'update attribute',
409 - payload: {tabIndex: 42},
410 - },
411 - {
412 - instanceID: inst._debugID,
413 - type: 'mount',
414 - payload: 'MY-COMPONENT',
415 - },
416 - ]);
417 - });
418 -
419 - it('gets recorded during an update', () => {
420 - var node = document.createElement('div');
421 - ReactDOM.render(<my-component />, node);
422 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
423 -
424 - ReactHostOperationHistoryHook._preventClearing = true;
425 - ReactDOM.render(<my-component className="rad" />, node);
426 - ReactDOM.render(<my-component className="mad" tabIndex={42} />, node);
427 - ReactDOM.render(<my-component tabIndex={43} />, node);
428 -
429 - assertHistoryMatches([
430 - {
431 - instanceID: inst._debugID,
432 - type: 'update attribute',
433 - payload: {className: 'rad'},
434 - },
435 - {
436 - instanceID: inst._debugID,
437 - type: 'update attribute',
438 - payload: {className: 'mad'},
439 - },
440 - {
441 - instanceID: inst._debugID,
442 - type: 'update attribute',
443 - payload: {tabIndex: 42},
444 - },
445 - {
446 - instanceID: inst._debugID,
447 - type: 'remove attribute',
448 - payload: 'className',
449 - },
450 - {
451 - instanceID: inst._debugID,
452 - type: 'update attribute',
453 - payload: {tabIndex: 43},
454 - },
455 - ]);
456 - });
457 - });
458 - });
459 -
460 - describe('replace text', () => {
461 - describe('text content', () => {
462 - it('gets recorded during an update from text content', () => {
463 - var node = document.createElement('div');
464 - ReactDOM.render(<div>Hi.</div>, node);
465 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
466 -
467 - ReactHostOperationHistoryHook._preventClearing = true;
468 - ReactDOM.render(<div>Bye.</div>, node);
469 -
470 - assertHistoryMatches([
471 - {
472 - instanceID: inst._debugID,
473 - type: 'replace text',
474 - payload: 'Bye.',
475 - },
476 - ]);
477 - });
478 -
479 - it('gets recorded during an update from html', () => {
480 - var node = document.createElement('div');
481 - ReactDOM.render(
482 - <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
483 - node,
484 - );
485 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
486 -
487 - ReactHostOperationHistoryHook._preventClearing = true;
488 - ReactDOM.render(<div>Bye.</div>, node);
489 -
490 - assertHistoryMatches([
491 - {
492 - instanceID: inst._debugID,
493 - type: 'replace text',
494 - payload: 'Bye.',
495 - },
496 - ]);
497 - });
498 -
499 - it('gets recorded during an update from children', () => {
500 - var node = document.createElement('div');
501 - ReactDOM.render(<div><span /><p /></div>, node);
502 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
503 -
504 - ReactHostOperationHistoryHook._preventClearing = true;
505 - ReactDOM.render(<div>Bye.</div>, node);
506 -
507 - assertHistoryMatches([
508 - {
509 - instanceID: inst._debugID,
510 - type: 'remove child',
511 - payload: {fromIndex: 0},
512 - },
513 - {
514 - instanceID: inst._debugID,
515 - type: 'remove child',
516 - payload: {fromIndex: 1},
517 - },
518 - {
519 - instanceID: inst._debugID,
520 - type: 'replace text',
521 - payload: 'Bye.',
522 - },
523 - ]);
524 - });
525 -
526 - it('gets ignored if new text is equal', () => {
527 - var node = document.createElement('div');
528 - ReactDOM.render(<div>Hi.</div>, node);
529 -
530 - ReactHostOperationHistoryHook._preventClearing = true;
531 - ReactDOM.render(<div>Hi.</div>, node);
532 -
533 - assertHistoryMatches([]);
534 - });
535 - });
536 -
537 - describe('text node', () => {
538 - it('gets recorded during an update', () => {
539 - var node = document.createElement('div');
540 - ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
541 - var inst1 = ReactDOMComponentTree.getInstanceFromNode(
542 - node.firstChild.childNodes[0],
543 - );
544 - var inst2 = ReactDOMComponentTree.getInstanceFromNode(
545 - node.firstChild.childNodes[3],
546 - );
547 -
548 - ReactHostOperationHistoryHook._preventClearing = true;
549 - ReactDOM.render(<div>{'Bye.'}{43}</div>, node);
550 -
551 - assertHistoryMatches([
552 - {
553 - instanceID: inst1._debugID,
554 - type: 'replace text',
555 - payload: 'Bye.',
556 - },
557 - {
558 - instanceID: inst2._debugID,
559 - type: 'replace text',
560 - payload: '43',
561 - },
562 - ]);
563 - });
564 -
565 - it('gets ignored if new text is equal', () => {
566 - var node = document.createElement('div');
567 - ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
568 -
569 - ReactHostOperationHistoryHook._preventClearing = true;
570 - ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
571 -
572 - assertHistoryMatches([]);
573 - });
574 - });
575 - });
576 -
577 - describe('replace with', () => {
578 - it('gets recorded when composite renders to a different type', () => {
579 - var element;
580 - function Foo() {
581 - return element;
582 - }
583 -
584 - var node = document.createElement('div');
585 - element = <div />;
586 - ReactDOM.render(<Foo />, node);
587 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
588 -
589 - element = <span />;
590 -
591 - ReactHostOperationHistoryHook._preventClearing = true;
592 - ReactDOM.render(<Foo />, node);
593 -
594 - assertHistoryMatches([
595 - {
596 - instanceID: inst._debugID,
597 - type: 'replace with',
598 - payload: 'SPAN',
599 - },
600 - ]);
601 - });
602 -
603 - it('gets recorded when composite renders to null after a native', () => {
604 - var element;
605 - function Foo() {
606 - return element;
607 - }
608 -
609 - var node = document.createElement('div');
610 - element = <span />;
611 - ReactDOM.render(<Foo />, node);
612 -
613 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
614 - element = null;
615 -
616 - ReactHostOperationHistoryHook._preventClearing = true;
617 - ReactDOM.render(<Foo />, node);
618 -
619 - assertHistoryMatches([
620 - {
621 - instanceID: inst._debugID,
622 - type: 'replace with',
623 - payload: '#comment',
624 - },
625 - ]);
626 - });
627 -
628 - it('gets ignored if the type has not changed', () => {
629 - var element;
630 - function Foo() {
631 - return element;
632 - }
633 -
634 - var node = document.createElement('div');
635 - element = <div />;
636 - ReactDOM.render(<Foo />, node);
637 -
638 - element = <div />;
639 -
640 - ReactHostOperationHistoryHook._preventClearing = true;
641 - ReactDOM.render(<Foo />, node);
642 -
643 - assertHistoryMatches([]);
644 - });
645 - });
646 -
647 - describe('replace children', () => {
648 - it('gets recorded during an update from text content', () => {
649 - var node = document.createElement('div');
650 - ReactDOM.render(<div>Hi.</div>, node);
651 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
652 -
653 - ReactHostOperationHistoryHook._preventClearing = true;
654 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
655 -
656 - assertHistoryMatches([
657 - {
658 - instanceID: inst._debugID,
659 - type: 'replace children',
660 - payload: 'Bye.',
661 - },
662 - ]);
663 - });
664 -
665 - it('gets recorded during an update from html', () => {
666 - var node = document.createElement('div');
667 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
668 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
669 -
670 - ReactHostOperationHistoryHook._preventClearing = true;
671 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
672 -
673 - assertHistoryMatches([
674 - {
675 - instanceID: inst._debugID,
676 - type: 'replace children',
677 - payload: 'Bye.',
678 - },
679 - ]);
680 - });
681 -
682 - it('gets recorded during an update from children', () => {
683 - var node = document.createElement('div');
684 - ReactDOM.render(<div><span /><p /></div>, node);
685 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
686 -
687 - ReactHostOperationHistoryHook._preventClearing = true;
688 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
689 -
690 - assertHistoryMatches([
691 - {
692 - instanceID: inst._debugID,
693 - type: 'remove child',
694 - payload: {fromIndex: 0},
695 - },
696 - {
697 - instanceID: inst._debugID,
698 - type: 'remove child',
699 - payload: {fromIndex: 1},
700 - },
701 - {
702 - instanceID: inst._debugID,
703 - type: 'replace children',
704 - payload: 'Hi.',
705 - },
706 - ]);
707 - });
708 -
709 - it('gets ignored if new html is equal', () => {
710 - var node = document.createElement('div');
711 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
712 -
713 - ReactHostOperationHistoryHook._preventClearing = true;
714 - ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
715 -
716 - assertHistoryMatches([]);
717 - });
718 - });
719 -
720 - describe('insert child', () => {
721 - it('gets reported when a child is inserted', () => {
722 - var node = document.createElement('div');
723 - ReactDOM.render(<div><span /></div>, node);
724 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
725 -
726 - ReactHostOperationHistoryHook._preventClearing = true;
727 - ReactDOM.render(<div><span /><p /></div>, node);
728 -
729 - assertHistoryMatches([
730 - {
731 - instanceID: inst._debugID,
732 - type: 'insert child',
733 - payload: {toIndex: 1, content: 'P'},
734 - },
735 - ]);
736 - });
737 - });
738 -
739 - describe('move child', () => {
740 - it('gets reported when a child is inserted', () => {
741 - var node = document.createElement('div');
742 - ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);
743 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
744 -
745 - ReactHostOperationHistoryHook._preventClearing = true;
746 - ReactDOM.render(<div><p key="b" /><span key="a" /></div>, node);
747 -
748 - assertHistoryMatches([
749 - {
750 - instanceID: inst._debugID,
751 - type: 'move child',
752 - payload: {fromIndex: 0, toIndex: 1},
753 - },
754 - ]);
755 - });
756 - });
757 -
758 - describe('remove child', () => {
759 - it('gets reported when a child is removed', () => {
760 - var node = document.createElement('div');
761 - ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);
762 - var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
763 -
764 - ReactHostOperationHistoryHook._preventClearing = true;
765 - ReactDOM.render(<div><span key="a" /></div>, node);
766 -
767 - assertHistoryMatches([
768 - {
769 - instanceID: inst._debugID,
770 - type: 'remove child',
771 - payload: {fromIndex: 1},
772 - },
773 - ]);
774 - });
775 - });
776 -});
src/renderers/__tests__/ReactPerf-test.js deleted
-741
@@ -1,741 +0,0 @@
1 -/**
2 - * Copyright (c) 2013-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -// ReactPerf is currently not supported on Fiber.
13 -// Use browser timeline integration instead.
14 -describe.skip('ReactPerf', () => {
15 - var React;
16 - var ReactDOM;
17 - var ReactPerf;
18 - var ReactTestUtils;
19 - var emptyFunction;
20 -
21 - var App;
22 - var Box;
23 - var Div;
24 - var LifeCycle;
25 -
26 - beforeEach(() => {
27 - var now = 0;
28 - jest.setMock('fbjs/lib/performanceNow', function() {
29 - return now++;
30 - });
31 -
32 - if (typeof console.table !== 'function') {
33 - console.table = () => {};
34 - console.table.isFake = true;
35 - }
36 -
37 - React = require('react');
38 - ReactDOM = require('react-dom');
39 - ReactPerf = require('ReactPerf');
40 - ReactTestUtils = require('react-dom/test-utils');
41 - emptyFunction = require('fbjs/lib/emptyFunction');
42 -
43 - App = class extends React.Component {
44 - render() {
45 - return <div><Box /><Box flip={this.props.flipSecond} /></div>;
46 - }
47 - };
48 -
49 - Box = class extends React.Component {
50 - render() {
51 - return <div key={!!this.props.flip}><input /></div>;
52 - }
53 - };
54 -
55 - // ReactPerf only measures composites, so we put everything in one.
56 - Div = class extends React.Component {
57 - render() {
58 - return <div {...this.props} />;
59 - }
60 - };
61 -
62 - LifeCycle = class extends React.Component {
63 - shouldComponentUpdate = emptyFunction.thatReturnsTrue;
64 - componentWillMount = emptyFunction;
65 - componentDidMount = emptyFunction;
66 - componentWillReceiveProps = emptyFunction;
67 - componentWillUpdate = emptyFunction;
68 - componentDidUpdate = emptyFunction;
69 - componentWillUnmount = emptyFunction;
70 - render = emptyFunction.thatReturnsNull;
71 - };
72 - });
73 -
74 - afterEach(() => {
75 - if (console.table.isFake) {
76 - delete console.table;
77 - }
78 - });
79 -
80 - function measure(fn) {
81 - ReactPerf.start();
82 - fn();
83 - ReactPerf.stop();
84 -
85 - // Make sure none of the methods crash.
86 - ReactPerf.getWasted();
87 - ReactPerf.getInclusive();
88 - ReactPerf.getExclusive();
89 - ReactPerf.getOperations();
90 -
91 - return ReactPerf.getLastMeasurements();
92 - }
93 -
94 - it('should count no-op update as waste', () => {
95 - var container = document.createElement('div');
96 - ReactDOM.render(<App />, container);
97 - var measurements = measure(() => {
98 - ReactDOM.render(<App />, container);
99 - });
100 -
101 - var summary = ReactPerf.getWasted(measurements);
102 - expect(summary).toEqual([
103 - {
104 - key: 'App',
105 - instanceCount: 1,
106 - inclusiveRenderDuration: 3,
107 - renderCount: 1,
108 - },
109 - {
110 - key: 'App > Box',
111 - instanceCount: 2,
112 - inclusiveRenderDuration: 2,
113 - renderCount: 2,
114 - },
115 - ]);
116 - });
117 -
118 - it('should count no-op update in child as waste', () => {
119 - var container = document.createElement('div');
120 - ReactDOM.render(<App />, container);
121 -
122 - // Here, we add a Box -- two of the <Box /> updates are wasted time (but the
123 - // addition of the third is not)
124 - var measurements = measure(() => {
125 - ReactDOM.render(<App flipSecond={true} />, container);
126 - });
127 -
128 - var summary = ReactPerf.getWasted(measurements);
129 - expect(summary).toEqual([
130 - {
131 - key: 'App > Box',
132 - instanceCount: 1,
133 - inclusiveRenderDuration: 1,
134 - renderCount: 1,
135 - },
136 - ]);
137 - });
138 -
139 - function expectNoWaste(fn) {
140 - var measurements = measure(fn);
141 - var summary = ReactPerf.getWasted(measurements);
142 - expect(summary).toEqual([]);
143 - }
144 -
145 - it('should not count initial render as waste', () => {
146 - expectNoWaste(() => {
147 - ReactTestUtils.renderIntoDocument(<App />);
148 - });
149 - });
150 -
151 - it('should not count unmount as waste', () => {
152 - var container = document.createElement('div');
153 - ReactDOM.render(<Div>hello</Div>, container);
154 - expectNoWaste(() => {
155 - ReactDOM.unmountComponentAtNode(container);
156 - });
157 - });
158 -
159 - it('should not count content update as waste', () => {
160 - var container = document.createElement('div');
161 - ReactDOM.render(<Div>hello</Div>, container);
162 - expectNoWaste(() => {
163 - ReactDOM.render(<Div>hello world</Div>, container);
164 - });
165 - });
166 -
167 - it('should not count child addition as waste', () => {
168 - var container = document.createElement('div');
169 - ReactDOM.render(<Div><span /></Div>, container);
170 - expectNoWaste(() => {
171 - ReactDOM.render(<Div><span /><span /></Div>, container);
172 - });
173 - });
174 -
175 - it('should not count child removal as waste', () => {
176 - var container = document.createElement('div');
177 - ReactDOM.render(<Div><span /><span /></Div>, container);
178 - expectNoWaste(() => {
179 - ReactDOM.render(<Div><span /></Div>, container);
180 - });
181 - });
182 -
183 - it('should not count property update as waste', () => {
184 - var container = document.createElement('div');
185 - ReactDOM.render(<Div className="yellow">hey</Div>, container);
186 - expectNoWaste(() => {
187 - ReactDOM.render(<Div className="blue">hey</Div>, container);
188 - });
189 - });
190 -
191 - it('should not count style update as waste', () => {
192 - var container = document.createElement('div');
193 - ReactDOM.render(<Div style={{color: 'yellow'}}>hey</Div>, container);
194 - expectNoWaste(() => {
195 - ReactDOM.render(<Div style={{color: 'blue'}}>hey</Div>, container);
196 - });
197 - });
198 -
199 - it('should not count property removal as waste', () => {
200 - var container = document.createElement('div');
201 - ReactDOM.render(<Div className="yellow">hey</Div>, container);
202 - expectNoWaste(() => {
203 - ReactDOM.render(<Div>hey</Div>, container);
204 - });
205 - });
206 -
207 - it('should not count raw HTML update as waste', () => {
208 - var container = document.createElement('div');
209 - ReactDOM.render(
210 - <Div dangerouslySetInnerHTML={{__html: 'me'}} />,
211 - container,
212 - );
213 - expectNoWaste(() => {
214 - ReactDOM.render(
215 - <Div dangerouslySetInnerHTML={{__html: 'you'}} />,
216 - container,
217 - );
218 - });
219 - });
220 -
221 - it('should not count child reordering as waste', () => {
222 - var container = document.createElement('div');
223 - ReactDOM.render(<Div><div key="A" /><div key="B" /></Div>, container);
224 - expectNoWaste(() => {
225 - ReactDOM.render(<Div><div key="B" /><div key="A" /></Div>, container);
226 - });
227 - });
228 -
229 - it('should not count text update as waste', () => {
230 - var container = document.createElement('div');
231 - ReactDOM.render(<Div>{'hello'}{'world'}</Div>, container);
232 - expectNoWaste(() => {
233 - ReactDOM.render(<Div>{'hello'}{'friend'}</Div>, container);
234 - });
235 - });
236 -
237 - it('should not count replacing null with a host as waste', () => {
238 - var element = null;
239 - function Foo() {
240 - return element;
241 - }
242 - var container = document.createElement('div');
243 - ReactDOM.render(<Foo />, container);
244 - expectNoWaste(() => {
245 - element = <div />;
246 - ReactDOM.render(<Foo />, container);
247 - });
248 - });
249 -
250 - it('should not count replacing a host with null as waste', () => {
251 - var element = <div />;
252 - function Foo() {
253 - return element;
254 - }
255 - var container = document.createElement('div');
256 - ReactDOM.render(<Foo />, container);
257 - expectNoWaste(() => {
258 - element = null;
259 - ReactDOM.render(<Foo />, container);
260 - });
261 - });
262 -
263 - it('should include stats for components unmounted during measurement', () => {
264 - var container = document.createElement('div');
265 - var measurements = measure(() => {
266 - ReactDOM.render(<Div><Div key="a" /></Div>, container);
267 - ReactDOM.render(<Div><Div key="b" /></Div>, container);
268 - });
269 - expect(ReactPerf.getExclusive(measurements)).toEqual([
270 - {
271 - key: 'Div',
272 - instanceCount: 3,
273 - counts: {ctor: 3, render: 4},
274 - durations: {ctor: 3, render: 4},
275 - totalDuration: 7,
276 - },
277 - ]);
278 - });
279 -
280 - it('should include lifecycle methods in measurements', () => {
281 - var container = document.createElement('div');
282 - var measurements = measure(() => {
283 - var instance = ReactDOM.render(<LifeCycle />, container);
284 - ReactDOM.render(<LifeCycle />, container);
285 - instance.setState({});
286 - ReactDOM.unmountComponentAtNode(container);
287 - });
288 - expect(ReactPerf.getExclusive(measurements)).toEqual([
289 - {
290 - key: 'LifeCycle',
291 - instanceCount: 1,
292 - totalDuration: 14,
293 - counts: {
294 - ctor: 1,
295 - shouldComponentUpdate: 2,
296 - componentWillMount: 1,
297 - componentDidMount: 1,
298 - componentWillReceiveProps: 1,
299 - componentWillUpdate: 2,
300 - componentDidUpdate: 2,
301 - componentWillUnmount: 1,
302 - render: 3,
303 - },
304 - durations: {
305 - ctor: 1,
306 - shouldComponentUpdate: 2,
307 - componentWillMount: 1,
308 - componentDidMount: 1,
309 - componentWillReceiveProps: 1,
310 - componentWillUpdate: 2,
311 - componentDidUpdate: 2,
312 - componentWillUnmount: 1,
313 - render: 3,
314 - },
315 - },
316 - ]);
317 - });
318 -
319 - it('should include render time of functional components', () => {
320 - function Foo() {
321 - return null;
322 - }
323 -
324 - var container = document.createElement('div');
325 - var measurements = measure(() => {
326 - ReactDOM.render(<Foo />, container);
327 - });
328 - expect(ReactPerf.getExclusive(measurements)).toEqual([
329 - {
330 - key: 'Foo',
331 - instanceCount: 1,
332 - totalDuration: 1,
333 - counts: {
334 - render: 1,
335 - },
336 - durations: {
337 - render: 1,
338 - },
339 - },
340 - ]);
341 - });
342 -
343 - it('should not count time in a portal towards lifecycle method', () => {
344 - function Foo() {
345 - return null;
346 - }
347 -
348 - var portalContainer = document.createElement('div');
349 - class Portal extends React.Component {
350 - componentDidMount() {
351 - ReactDOM.render(<Foo />, portalContainer);
352 - }
353 - render() {
354 - return null;
355 - }
356 - }
357 -
358 - var container = document.createElement('div');
359 - var measurements = measure(() => {
360 - ReactDOM.render(<Portal />, container);
361 - });
362 -
363 - expect(ReactPerf.getExclusive(measurements)).toEqual([
364 - {
365 - key: 'Portal',
366 - instanceCount: 1,
367 - totalDuration: 6,
368 - counts: {
369 - ctor: 1,
370 - componentDidMount: 1,
371 - render: 1,
372 - },
373 - durations: {
374 - ctor: 1,
375 - // We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
376 - // Otherwise it would artificially float to the top even though its exclusive time is small.
377 - // This is how we get 4 as a number with the performanceNow() mock:
378 - // - we capture the time we enter componentDidMount (n = 0)
379 - // - we capture the time when we enter a nested flush (n = 1)
380 - // - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
381 - // - we capture the time when we exit a nested flush (n = 4)
382 - // - we capture the time we exit componentDidMount (n = 5)
383 - // Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
384 - componentDidMount: 4,
385 - render: 1,
386 - },
387 - },
388 - {
389 - key: 'Foo',
390 - instanceCount: 1,
391 - totalDuration: 1,
392 - counts: {
393 - render: 1,
394 - },
395 - durations: {
396 - render: 1,
397 - },
398 - },
399 - ]);
400 - });
401 -
402 - it('warns once when using getMeasurementsSummaryMap', () => {
403 - var measurements = measure(() => {});
404 - spyOn(console, 'warn');
405 - ReactPerf.getMeasurementsSummaryMap(measurements);
406 - expectDev(console.warn.calls.count()).toBe(1);
407 - expectDev(console.warn.calls.argsFor(0)[0]).toContain(
408 - '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
409 - '`ReactPerf.getWasted(...)` instead.',
410 - );
411 -
412 - ReactPerf.getMeasurementsSummaryMap(measurements);
413 - expectDev(console.warn.calls.count()).toBe(1);
414 - });
415 -
416 - it('warns once when using printDOM', () => {
417 - var measurements = measure(() => {});
418 - spyOn(console, 'warn');
419 - ReactPerf.printDOM(measurements);
420 - expectDev(console.warn.calls.count()).toBe(1);
421 - expectDev(console.warn.calls.argsFor(0)[0]).toContain(
422 - '`ReactPerf.printDOM(...)` is deprecated. Use ' +
423 - '`ReactPerf.printOperations(...)` instead.',
424 - );
425 -
426 - ReactPerf.printDOM(measurements);
427 - expectDev(console.warn.calls.count()).toBe(1);
428 - });
429 -
430 - it('returns isRunning state', () => {
431 - expect(ReactPerf.isRunning()).toBe(false);
432 -
433 - ReactPerf.start();
434 - expect(ReactPerf.isRunning()).toBe(true);
435 -
436 - ReactPerf.stop();
437 - expect(ReactPerf.isRunning()).toBe(false);
438 - });
439 -
440 - it('start has no effect when already running', () => {
441 - expect(ReactPerf.isRunning()).toBe(false);
442 -
443 - ReactPerf.start();
444 - expect(ReactPerf.isRunning()).toBe(true);
445 -
446 - ReactPerf.start();
447 - expect(ReactPerf.isRunning()).toBe(true);
448 -
449 - ReactPerf.stop();
450 - expect(ReactPerf.isRunning()).toBe(false);
451 - });
452 -
453 - it('stop has no effect when already stopped', () => {
454 - expect(ReactPerf.isRunning()).toBe(false);
455 -
456 - ReactPerf.stop();
457 - expect(ReactPerf.isRunning()).toBe(false);
458 -
459 - ReactPerf.stop();
460 - expect(ReactPerf.isRunning()).toBe(false);
461 - });
462 -
463 - it('should print console error only once', () => {
464 - __DEV__ = false;
465 -
466 - spyOn(console, 'error');
467 -
468 - expect(ReactPerf.getLastMeasurements()).toEqual([]);
469 - expect(ReactPerf.getExclusive()).toEqual([]);
470 - expect(ReactPerf.getInclusive()).toEqual([]);
471 - expect(ReactPerf.getWasted()).toEqual([]);
472 - expect(ReactPerf.getOperations()).toEqual([]);
473 - expect(ReactPerf.printExclusive()).toEqual(undefined);
474 - expect(ReactPerf.printInclusive()).toEqual(undefined);
475 - expect(ReactPerf.printWasted()).toEqual(undefined);
476 - expect(ReactPerf.printOperations()).toEqual(undefined);
477 - expect(ReactPerf.start()).toBe(undefined);
478 - expect(ReactPerf.stop()).toBe(undefined);
479 - expect(ReactPerf.isRunning()).toBe(false);
480 -
481 - expectDev(console.error.calls.count()).toBe(1);
482 -
483 - __DEV__ = true;
484 - });
485 -
486 - it('should work when measurement starts during reconciliation', () => {
487 - // https://github.com/facebook/react/issues/6949#issuecomment-230371009
488 - class Measurer extends React.Component {
489 - componentWillMount() {
490 - ReactPerf.start();
491 - }
492 -
493 - componentDidMount() {
494 - ReactPerf.stop();
495 - }
496 -
497 - componentWillUpdate() {
498 - ReactPerf.start();
499 - }
500 -
501 - componentDidUpdate() {
502 - ReactPerf.stop();
503 - }
504 -
505 - render() {
506 - // Force reconciliation despite constant element
507 - return React.cloneElement(this.props.children);
508 - }
509 - }
510 -
511 - var container = document.createElement('div');
512 - ReactDOM.render(<Measurer><App /></Measurer>, container);
513 - expect(ReactPerf.getWasted()).toEqual([]);
514 -
515 - ReactDOM.render(<Measurer><App /></Measurer>, container);
516 - expect(ReactPerf.getWasted()).toEqual([
517 - {
518 - key: 'Measurer',
519 - instanceCount: 1,
520 - inclusiveRenderDuration: 4,
521 - renderCount: 1,
522 - },
523 - {
524 - key: 'App',
525 - instanceCount: 1,
526 - inclusiveRenderDuration: 3,
527 - renderCount: 1,
528 - },
529 - {
530 - key: 'App > Box',
531 - instanceCount: 2,
532 - inclusiveRenderDuration: 2,
533 - renderCount: 2,
534 - },
535 - ]);
536 - });
537 -
538 - it('should not print errant warnings if render() throws', () => {
539 - var container = document.createElement('div');
540 - var thrownErr = new Error('Muhaha!');
541 -
542 - class Evil extends React.Component {
543 - render() {
544 - throw thrownErr;
545 - }
546 - }
547 -
548 - ReactPerf.start();
549 - try {
550 - ReactDOM.render(
551 - <div>
552 - <LifeCycle />
553 - <Evil />
554 - </div>,
555 - container,
556 - );
557 - } catch (err) {
558 - if (err !== thrownErr) {
559 - throw err;
560 - }
561 - }
562 - ReactPerf.stop();
563 - });
564 -
565 - it('should not print errant warnings if componentWillMount() throws', () => {
566 - var container = document.createElement('div');
567 - var thrownErr = new Error('Muhaha!');
568 -
569 - class Evil extends React.Component {
570 - componentWillMount() {
571 - throw thrownErr;
572 - }
573 - render() {
574 - return <div />;
575 - }
576 - }
577 -
578 - ReactPerf.start();
579 - try {
580 - ReactDOM.render(
581 - <div>
582 - <LifeCycle />
583 - <Evil />
584 - </div>,
585 - container,
586 - );
587 - } catch (err) {
588 - if (err !== thrownErr) {
589 - throw err;
590 - }
591 - }
592 - ReactPerf.stop();
593 - });
594 -
595 - it('should not print errant warnings if componentDidMount() throws', () => {
596 - var container = document.createElement('div');
597 - var thrownErr = new Error('Muhaha!');
598 -
599 - class Evil extends React.Component {
600 - componentDidMount() {
601 - throw thrownErr;
602 - }
603 - render() {
604 - return <div />;
605 - }
606 - }
607 -
608 - ReactPerf.start();
609 - try {
610 - ReactDOM.render(
611 - <div>
612 - <LifeCycle />
613 - <Evil />
614 - </div>,
615 - container,
616 - );
617 - } catch (err) {
618 - if (err !== thrownErr) {
619 - throw err;
620 - }
621 - }
622 - ReactPerf.stop();
623 - });
624 -
625 - it('should not print errant warnings if portal throws in render()', () => {
626 - var container = document.createElement('div');
627 - var thrownErr = new Error('Muhaha!');
628 -
629 - class Evil extends React.Component {
630 - render() {
631 - throw thrownErr;
632 - }
633 - }
634 - class EvilPortal extends React.Component {
635 - componentDidMount() {
636 - var portalContainer = document.createElement('div');
637 - ReactDOM.render(<Evil />, portalContainer);
638 - }
639 - render() {
640 - return <div />;
641 - }
642 - }
643 -
644 - ReactPerf.start();
645 - try {
646 - ReactDOM.render(
647 - <div>
648 - <LifeCycle />
649 - <EvilPortal />
650 - </div>,
651 - container,
652 - );
653 - } catch (err) {
654 - if (err !== thrownErr) {
655 - throw err;
656 - }
657 - }
658 - ReactDOM.unmountComponentAtNode(container);
659 - ReactPerf.stop();
660 - });
661 -
662 - it('should not print errant warnings if portal throws in componentWillMount()', () => {
663 - var container = document.createElement('div');
664 - var thrownErr = new Error('Muhaha!');
665 -
666 - class Evil extends React.Component {
667 - componentWillMount() {
668 - throw thrownErr;
669 - }
670 - render() {
671 - return <div />;
672 - }
673 - }
674 - class EvilPortal extends React.Component {
675 - componentWillMount() {
676 - var portalContainer = document.createElement('div');
677 - ReactDOM.render(<Evil />, portalContainer);
678 - }
679 - render() {
680 - return <div />;
681 - }
682 - }
683 -
684 - ReactPerf.start();
685 - try {
686 - ReactDOM.render(
687 - <div>
688 - <LifeCycle />
689 - <EvilPortal />
690 - </div>,
691 - container,
692 - );
693 - } catch (err) {
694 - if (err !== thrownErr) {
695 - throw err;
696 - }
697 - }
698 - ReactDOM.unmountComponentAtNode(container);
699 - ReactPerf.stop();
700 - });
701 -
702 - it('should not print errant warnings if portal throws in componentDidMount()', () => {
703 - var container = document.createElement('div');
704 - var thrownErr = new Error('Muhaha!');
705 -
706 - class Evil extends React.Component {
707 - componentDidMount() {
708 - throw thrownErr;
709 - }
710 - render() {
711 - return <div />;
712 - }
713 - }
714 - class EvilPortal extends React.Component {
715 - componentDidMount() {
716 - var portalContainer = document.createElement('div');
717 - ReactDOM.render(<Evil />, portalContainer);
718 - }
719 - render() {
720 - return <div />;
721 - }
722 - }
723 -
724 - ReactPerf.start();
725 - try {
726 - ReactDOM.render(
727 - <div>
728 - <LifeCycle />
729 - <EvilPortal />
730 - </div>,
731 - container,
732 - );
733 - } catch (err) {
734 - if (err !== thrownErr) {
735 - throw err;
736 - }
737 - }
738 - ReactDOM.unmountComponentAtNode(container);
739 - ReactPerf.stop();
740 - });
741 -});
src/renderers/dom/shared/DOMPropertyOperations.js
-27
@@ -10,8 +10,6 @@
10 'use strict';
11
12 var DOMProperty = require('DOMProperty');
13 -var ReactDOMComponentTree = require('ReactDOMComponentTree');
14 -var ReactInstrumentation = require('ReactInstrumentation');
13
14 if (__DEV__) {
15 var warning = require('fbjs/lib/warning');
@@ -201,11 +199,6 @@ var DOMPropertyOperations = {
199 if (__DEV__) {
200 var payload = {};
201 payload[name] = value;
204 - ReactInstrumentation.debugTool.onHostOperation({
205 - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
206 - type: 'update attribute',
207 - payload: payload,
208 - });
202 }
203 },
204
@@ -222,11 +215,6 @@ var DOMPropertyOperations = {
215 if (__DEV__) {
216 var payload = {};
217 payload[name] = value;
225 - ReactInstrumentation.debugTool.onHostOperation({
226 - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
227 - type: 'update attribute',
228 - payload: payload,
229 - });
218 }
219 },
220
@@ -238,13 +226,6 @@ var DOMPropertyOperations = {
226 */
227 deleteValueForAttribute: function(node, name) {
228 node.removeAttribute(name);
241 - if (__DEV__) {
242 - ReactInstrumentation.debugTool.onHostOperation({
243 - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
244 - type: 'remove attribute',
245 - payload: name,
246 - });
247 - }
229 },
230
231 /**
@@ -272,14 +253,6 @@ var DOMPropertyOperations = {
253 } else {
254 node.removeAttribute(name);
255 }
275 -
276 - if (__DEV__) {
277 - ReactInstrumentation.debugTool.onHostOperation({
278 - instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
279 - type: 'remove attribute',
280 - payload: name,
281 - });
282 - }
256 },
257 };
258
src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js
+14 -36
@@ -22,27 +22,17 @@ var hasOwnProperty = Object.prototype.hasOwnProperty;
22
23 if (__DEV__) {
24 var warning = require('fbjs/lib/warning');
25 - var {
26 - ReactComponentTreeHook,
27 - ReactDebugCurrentFrame,
28 - } = require('ReactGlobalSharedState');
29 - var {getStackAddendumByID} = ReactComponentTreeHook;
25 + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
26
27 var validAriaProperties = require('./validAriaProperties');
28 }
29
34 -function getStackAddendum(debugID) {
35 - if (debugID != null) {
36 - // This can only happen on Stack
37 - return getStackAddendumByID(debugID);
38 - } else {
39 - // This can only happen on Fiber / Server
40 - var stack = ReactDebugCurrentFrame.getStackAddendum();
41 - return stack != null ? stack : '';
42 - }
30 +function getStackAddendum() {
31 + var stack = ReactDebugCurrentFrame.getStackAddendum();
32 + return stack != null ? stack : '';
33 }
34
45 -function validateProperty(tagName, name, debugID) {
35 +function validateProperty(tagName, name) {
36 if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
37 return true;
38 }
@@ -60,7 +50,7 @@ function validateProperty(tagName, name, debugID) {
50 false,
51 'Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.%s',
52 name,
63 - getStackAddendum(debugID),
53 + getStackAddendum(),
54 );
55 warnedProperties[name] = true;
56 return true;
@@ -72,7 +62,7 @@ function validateProperty(tagName, name, debugID) {
62 'Invalid ARIA attribute `%s`. Did you mean `%s`?%s',
63 name,
64 correctName,
75 - getStackAddendum(debugID),
65 + getStackAddendum(),
66 );
67 warnedProperties[name] = true;
68 return true;
@@ -98,7 +88,7 @@ function validateProperty(tagName, name, debugID) {
88 'Unknown ARIA attribute `%s`. Did you mean `%s`?%s',
89 name,
90 standardName,
101 - getStackAddendum(debugID),
91 + getStackAddendum(),
92 );
93 warnedProperties[name] = true;
94 return true;
@@ -108,11 +98,11 @@ function validateProperty(tagName, name, debugID) {
98 return true;
99 }
100
111 -function warnInvalidARIAProps(type, props, debugID) {
101 +function warnInvalidARIAProps(type, props) {
102 const invalidProps = [];
103
104 for (var key in props) {
115 - var isValid = validateProperty(type, key, debugID);
105 + var isValid = validateProperty(type, key);
106 if (!isValid) {
107 invalidProps.push(key);
108 }
@@ -129,7 +119,7 @@ function warnInvalidARIAProps(type, props, debugID) {
119 'For details, see https://fb.me/invalid-aria-prop%s',
120 unknownPropString,
121 type,
132 - getStackAddendum(debugID),
122 + getStackAddendum(),
123 );
124 } else if (invalidProps.length > 1) {
125 warning(
@@ -138,32 +128,20 @@ function warnInvalidARIAProps(type, props, debugID) {
128 'For details, see https://fb.me/invalid-aria-prop%s',
129 unknownPropString,
130 type,
141 - getStackAddendum(debugID),
131 + getStackAddendum(),
132 );
133 }
134 }
135
146 -function validateProperties(type, props, debugID /* Stack only */) {
136 +function validateProperties(type, props) {
137 if (isCustomComponent(type, props)) {
138 return;
139 }
150 - warnInvalidARIAProps(type, props, debugID);
140 + warnInvalidARIAProps(type, props);
141 }
142
143 var ReactDOMInvalidARIAHook = {
154 - // Fiber
144 validateProperties,
156 - // Stack
157 - onBeforeMountComponent(debugID, element) {
158 - if (__DEV__ && element != null && typeof element.type === 'string') {
159 - validateProperties(element.type, element.props, debugID);
160 - }
161 - },
162 - onBeforeUpdateComponent(debugID, element) {
163 - if (__DEV__ && element != null && typeof element.type === 'string') {
164 - validateProperties(element.type, element.props, debugID);
165 - }
166 - },
145 };
146
147 module.exports = ReactDOMInvalidARIAHook;
src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js
+6 -28
@@ -11,27 +11,17 @@
11
12 if (__DEV__) {
13 var warning = require('fbjs/lib/warning');
14 - var {
15 - ReactComponentTreeHook,
16 - ReactDebugCurrentFrame,
17 - } = require('ReactGlobalSharedState');
18 - var {getStackAddendumByID} = ReactComponentTreeHook;
14 + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
15 }
16
17 var didWarnValueNull = false;
18
23 -function getStackAddendum(debugID) {
24 - if (debugID != null) {
25 - // This can only happen on Stack
26 - return getStackAddendumByID(debugID);
27 - } else {
28 - // This can only happen on Fiber / Server
29 - var stack = ReactDebugCurrentFrame.getStackAddendum();
30 - return stack != null ? stack : '';
31 - }
19 +function getStackAddendum() {
20 + var stack = ReactDebugCurrentFrame.getStackAddendum();
21 + return stack != null ? stack : '';
22 }
23
34 -function validateProperties(type, props, debugID /* Stack only */) {
24 +function validateProperties(type, props) {
25 if (type !== 'input' && type !== 'textarea' && type !== 'select') {
26 return;
27 }
@@ -42,7 +32,7 @@ function validateProperties(type, props, debugID /* Stack only */) {
32 'Consider using the empty string to clear the component or `undefined` ' +
33 'for uncontrolled components.%s',
34 type,
45 - getStackAddendum(debugID),
35 + getStackAddendum(),
36 );
37
38 didWarnValueNull = true;
@@ -50,19 +40,7 @@ function validateProperties(type, props, debugID /* Stack only */) {
40 }
41
42 var ReactDOMNullInputValuePropHook = {
53 - // Fiber
43 validateProperties,
55 - // Stack
56 - onBeforeMountComponent(debugID, element) {
57 - if (__DEV__ && element != null && typeof element.type === 'string') {
58 - validateProperties(element.type, element.props, debugID);
59 - }
60 - },
61 - onBeforeUpdateComponent(debugID, element) {
62 - if (__DEV__ && element != null && typeof element.type === 'string') {
63 - validateProperties(element.type, element.props, debugID);
64 - }
65 - },
44 };
45
46 module.exports = ReactDOMNullInputValuePropHook;
src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js
+18 -40
@@ -15,22 +15,12 @@ var isCustomComponent = require('isCustomComponent');
15
16 if (__DEV__) {
17 var warning = require('fbjs/lib/warning');
18 - var {
19 - ReactComponentTreeHook,
20 - ReactDebugCurrentFrame,
21 - } = require('ReactGlobalSharedState');
22 - var {getStackAddendumByID} = ReactComponentTreeHook;
18 + var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
19 }
20
25 -function getStackAddendum(debugID) {
26 - if (debugID != null) {
27 - // This can only happen on Stack
28 - return getStackAddendumByID(debugID);
29 - } else {
30 - // This can only happen on Fiber / Server
31 - var stack = ReactDebugCurrentFrame.getStackAddendum();
32 - return stack != null ? stack : '';
33 - }
21 +function getStackAddendum() {
22 + var stack = ReactDebugCurrentFrame.getStackAddendum();
23 + return stack != null ? stack : '';
24 }
25
26 if (__DEV__) {
@@ -43,7 +33,7 @@ if (__DEV__) {
33 );
34 var possibleStandardNames = require('possibleStandardNames');
35
46 - var validateProperty = function(tagName, name, value, debugID) {
36 + var validateProperty = function(tagName, name, value) {
37 if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
38 return true;
39 }
@@ -74,7 +64,7 @@ if (__DEV__) {
64 'Invalid event handler property `%s`. Did you mean `%s`?%s',
65 name,
66 registrationName,
77 - getStackAddendum(debugID),
67 + getStackAddendum(),
68 );
69 warnedProperties[name] = true;
70 return true;
@@ -85,7 +75,7 @@ if (__DEV__) {
75 false,
76 'Unknown event handler property `%s`. It will be ignored.%s',
77 name,
88 - getStackAddendum(debugID),
78 + getStackAddendum(),
79 );
80 warnedProperties[name] = true;
81 return true;
@@ -138,7 +128,7 @@ if (__DEV__) {
128 'Received a `%s` for string attribute `is`. If this is expected, cast ' +
129 'the value to a string.%s',
130 typeof value,
141 - getStackAddendum(debugID),
131 + getStackAddendum(),
132 );
133 warnedProperties[name] = true;
134 return true;
@@ -150,7 +140,7 @@ if (__DEV__) {
140 'Received NaN for numeric attribute `%s`. If this is expected, cast ' +
141 'the value to a string.%s',
142 name,
153 - getStackAddendum(debugID),
143 + getStackAddendum(),
144 );
145 warnedProperties[name] = true;
146 return true;
@@ -167,7 +157,7 @@ if (__DEV__) {
157 'Invalid DOM property `%s`. Did you mean `%s`?%s',
158 name,
159 standardName,
170 - getStackAddendum(debugID),
160 + getStackAddendum(),
161 );
162 warnedProperties[name] = true;
163 return true;
@@ -184,7 +174,7 @@ if (__DEV__) {
174 'it from the DOM element.%s',
175 name,
176 lowerCasedName,
187 - getStackAddendum(debugID),
177 + getStackAddendum(),
178 );
179 warnedProperties[name] = true;
180 return true;
@@ -197,7 +187,7 @@ if (__DEV__) {
187 'the value to a string.%s',
188 value,
189 name,
200 - getStackAddendum(debugID),
190 + getStackAddendum(),
191 );
192 warnedProperties[name] = true;
193 return true;
@@ -219,10 +209,10 @@ if (__DEV__) {
209 };
210 }
211
222 -var warnUnknownProperties = function(type, props, debugID) {
212 +var warnUnknownProperties = function(type, props) {
213 var unknownProps = [];
214 for (var key in props) {
225 - var isValid = validateProperty(type, key, props[key], debugID);
215 + var isValid = validateProperty(type, key, props[key]);
216 if (!isValid) {
217 unknownProps.push(key);
218 }
@@ -237,7 +227,7 @@ var warnUnknownProperties = function(type, props, debugID) {
227 'For details, see https://fb.me/react-attribute-behavior%s',
228 unknownPropString,
229 type,
240 - getStackAddendum(debugID),
230 + getStackAddendum(),
231 );
232 } else if (unknownProps.length > 1) {
233 warning(
@@ -247,32 +237,20 @@ var warnUnknownProperties = function(type, props, debugID) {
237 'For details, see https://fb.me/react-attribute-behavior%s',
238 unknownPropString,
239 type,
250 - getStackAddendum(debugID),
240 + getStackAddendum(),
241 );
242 }
243 };
244
255 -function validateProperties(type, props, debugID /* Stack only */) {
245 +function validateProperties(type, props) {
246 if (isCustomComponent(type, props)) {
247 return;
248 }
259 - warnUnknownProperties(type, props, debugID);
249 + warnUnknownProperties(type, props);
250 }
251
252 var ReactDOMUnknownPropertyHook = {
263 - // Fiber
253 validateProperties,
265 - // Stack
266 - onBeforeMountComponent(debugID, element) {
267 - if (__DEV__ && element != null && typeof element.type === 'string') {
268 - validateProperties(element.type, element.props, debugID);
269 - }
270 - },
271 - onBeforeUpdateComponent(debugID, element) {
272 - if (__DEV__ && element != null && typeof element.type === 'string') {
273 - validateProperties(element.type, element.props, debugID);
274 - }
275 - },
254 };
255
256 module.exports = ReactDOMUnknownPropertyHook;
src/renderers/native/ReactNativeFiberEntry.js
+13 -2
@@ -109,8 +109,19 @@ if (__DEV__) {
109 Object.assign(
110 ReactNativeFiber.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
111 {
112 - ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace
113 - ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf
112 + // TODO: none of these work since Fiber. Remove these dependencies.
113 + // Used by RCTRenderingPerf, Systrace:
114 + ReactDebugTool: {
115 + addHook() {},
116 + removeHook() {},
117 + },
118 + // Used by ReactPerfStallHandler, RCTRenderingPerf:
119 + ReactPerf: {
120 + start() {},
121 + stop() {},
122 + printInclusive() {},
123 + printWasted() {},
124 + },
125 },
126 );
127 }
src/renderers/shared/ReactDebugTool.js deleted
-439
@@ -1,439 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @providesModule ReactDebugTool
8 - * @flow
9 - */
10 -
11 -'use strict';
12 -
13 -var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook');
14 -var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
15 -var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
16 -var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
17 -
18 -var performanceNow = require('fbjs/lib/performanceNow');
19 -
20 -if (__DEV__) {
21 - var warning = require('fbjs/lib/warning');
22 -}
23 -
24 -import type {ReactElement} from 'ReactElementType';
25 -import type {DebugID} from 'ReactInstanceType';
26 -import type {Operation} from 'ReactHostOperationHistoryHook';
27 -
28 -type Hook = any;
29 -
30 -type TimerType =
31 - | 'ctor'
32 - | 'render'
33 - | 'componentWillMount'
34 - | 'componentWillUnmount'
35 - | 'componentWillReceiveProps'
36 - | 'shouldComponentUpdate'
37 - | 'componentWillUpdate'
38 - | 'componentDidUpdate'
39 - | 'componentDidMount';
40 -
41 -type Measurement = {
42 - timerType: TimerType,
43 - instanceID: DebugID,
44 - duration: number,
45 -};
46 -
47 -type TreeSnapshot = {
48 - [key: DebugID]: {
49 - displayName: string,
50 - text: string,
51 - updateCount: number,
52 - childIDs: Array<DebugID>,
53 - ownerID: DebugID,
54 - parentID: DebugID,
55 - },
56 -};
57 -
58 -type HistoryItem = {
59 - duration: number,
60 - measurements: Array<Measurement>,
61 - operations: Array<Operation>,
62 - treeSnapshot: TreeSnapshot,
63 -};
64 -
65 -export type FlushHistory = Array<HistoryItem>;
66 -
67 -// Trust the developer to only use this with a __DEV__ check
68 -var ReactDebugTool = ((null: any): typeof ReactDebugTool);
69 -
70 -if (__DEV__) {
71 - var hooks = [];
72 - var didHookThrowForEvent = {};
73 -
74 - const callHook = function(event, fn, context, arg1, arg2, arg3, arg4, arg5) {
75 - try {
76 - fn.call(context, arg1, arg2, arg3, arg4, arg5);
77 - } catch (e) {
78 - warning(
79 - didHookThrowForEvent[event],
80 - 'Exception thrown by hook while handling %s: %s',
81 - event,
82 - e + '\n' + e.stack,
83 - );
84 - didHookThrowForEvent[event] = true;
85 - }
86 - };
87 -
88 - const emitEvent = function(event, arg1, arg2, arg3, arg4, arg5) {
89 - for (var i = 0; i < hooks.length; i++) {
90 - var hook = hooks[i];
91 - var fn = hook[event];
92 - if (fn) {
93 - callHook(event, fn, hook, arg1, arg2, arg3, arg4, arg5);
94 - }
95 - }
96 - };
97 -
98 - var isProfiling = false;
99 - var flushHistory = [];
100 - var lifeCycleTimerStack = [];
101 - var currentFlushNesting = 0;
102 - var currentFlushMeasurements = [];
103 - var currentFlushStartTime = 0;
104 - var currentTimerDebugID = null;
105 - var currentTimerStartTime = 0;
106 - var currentTimerNestedFlushDuration = 0;
107 - var currentTimerType = null;
108 -
109 - var lifeCycleTimerHasWarned = false;
110 -
111 - const clearHistory = function() {
112 - ReactComponentTreeHook.purgeUnmountedComponents();
113 - ReactHostOperationHistoryHook.clearHistory();
114 - };
115 -
116 - const getTreeSnapshot = function(registeredIDs) {
117 - return registeredIDs.reduce((tree, id) => {
118 - var ownerID = ReactComponentTreeHook.getOwnerID(id);
119 - var parentID = ReactComponentTreeHook.getParentID(id);
120 - tree[id] = {
121 - displayName: ReactComponentTreeHook.getDisplayName(id),
122 - text: ReactComponentTreeHook.getText(id),
123 - updateCount: ReactComponentTreeHook.getUpdateCount(id),
124 - childIDs: ReactComponentTreeHook.getChildIDs(id),
125 - // Text nodes don't have owners but this is close enough.
126 - ownerID: ownerID ||
127 - (parentID && ReactComponentTreeHook.getOwnerID(parentID)) ||
128 - 0,
129 - parentID,
130 - };
131 - return tree;
132 - }, {});
133 - };
134 -
135 - const resetMeasurements = function() {
136 - var previousStartTime = currentFlushStartTime;
137 - var previousMeasurements = currentFlushMeasurements;
138 - var previousOperations = ReactHostOperationHistoryHook.getHistory();
139 -
140 - if (currentFlushNesting === 0) {
141 - currentFlushStartTime = 0;
142 - currentFlushMeasurements = [];
143 - clearHistory();
144 - return;
145 - }
146 -
147 - if (previousMeasurements.length || previousOperations.length) {
148 - var registeredIDs = ReactComponentTreeHook.getRegisteredIDs();
149 - flushHistory.push({
150 - duration: performanceNow() - previousStartTime,
151 - measurements: previousMeasurements || [],
152 - operations: previousOperations || [],
153 - treeSnapshot: getTreeSnapshot(registeredIDs),
154 - });
155 - }
156 -
157 - clearHistory();
158 - currentFlushStartTime = performanceNow();
159 - currentFlushMeasurements = [];
160 - };
161 -
162 - const checkDebugID = function(debugID, allowRoot = false) {
163 - if (allowRoot && debugID === 0) {
164 - return;
165 - }
166 - if (!debugID) {
167 - warning(false, 'ReactDebugTool: debugID may not be empty.');
168 - }
169 - };
170 -
171 - const beginLifeCycleTimer = function(debugID, timerType) {
172 - if (currentFlushNesting === 0) {
173 - return;
174 - }
175 - if (currentTimerType && !lifeCycleTimerHasWarned) {
176 - warning(
177 - false,
178 - 'There is an internal error in the React performance measurement code.' +
179 - '\n\nDid not expect %s timer to start while %s timer is still in ' +
180 - 'progress for %s instance.',
181 - timerType,
182 - currentTimerType || 'no',
183 - debugID === currentTimerDebugID ? 'the same' : 'another',
184 - );
185 - lifeCycleTimerHasWarned = true;
186 - }
187 - currentTimerStartTime = performanceNow();
188 - currentTimerNestedFlushDuration = 0;
189 - currentTimerDebugID = debugID;
190 - currentTimerType = timerType;
191 - };
192 -
193 - const endLifeCycleTimer = function(debugID, timerType) {
194 - if (currentFlushNesting === 0) {
195 - return;
196 - }
197 - if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) {
198 - warning(
199 - false,
200 - 'There is an internal error in the React performance measurement code. ' +
201 - 'We did not expect %s timer to stop while %s timer is still in ' +
202 - 'progress for %s instance. Please report this as a bug in React.',
203 - timerType,
204 - currentTimerType || 'no',
205 - debugID === currentTimerDebugID ? 'the same' : 'another',
206 - );
207 - lifeCycleTimerHasWarned = true;
208 - }
209 - if (isProfiling) {
210 - currentFlushMeasurements.push({
211 - timerType,
212 - instanceID: debugID,
213 - duration: performanceNow() -
214 - currentTimerStartTime -
215 - currentTimerNestedFlushDuration,
216 - });
217 - }
218 - currentTimerStartTime = 0;
219 - currentTimerNestedFlushDuration = 0;
220 - currentTimerDebugID = null;
221 - currentTimerType = null;
222 - };
223 -
224 - const pauseCurrentLifeCycleTimer = function() {
225 - var currentTimer = {
226 - startTime: currentTimerStartTime,
227 - nestedFlushStartTime: performanceNow(),
228 - debugID: currentTimerDebugID,
229 - timerType: currentTimerType,
230 - };
231 - lifeCycleTimerStack.push(currentTimer);
232 - currentTimerStartTime = 0;
233 - currentTimerNestedFlushDuration = 0;
234 - currentTimerDebugID = null;
235 - currentTimerType = null;
236 - };
237 -
238 - const resumeCurrentLifeCycleTimer = function() {
239 - var {
240 - startTime,
241 - nestedFlushStartTime,
242 - debugID,
243 - timerType,
244 - } = lifeCycleTimerStack.pop();
245 - var nestedFlushDuration = performanceNow() - nestedFlushStartTime;
246 - currentTimerStartTime = startTime;
247 - currentTimerNestedFlushDuration += nestedFlushDuration;
248 - currentTimerDebugID = debugID;
249 - currentTimerType = timerType;
250 - };
251 -
252 - var lastMarkTimeStamp = 0;
253 - var canUsePerformanceMeasure: boolean =
254 - typeof performance !== 'undefined' &&
255 - typeof performance.mark === 'function' &&
256 - typeof performance.clearMarks === 'function' &&
257 - typeof performance.measure === 'function' &&
258 - typeof performance.clearMeasures === 'function';
259 -
260 - const shouldMark = function(debugID) {
261 - if (!isProfiling || !canUsePerformanceMeasure) {
262 - return false;
263 - }
264 - var element = ReactComponentTreeHook.getElement(debugID);
265 - if (element == null || typeof element !== 'object') {
266 - return false;
267 - }
268 - var isHostElement = typeof element.type === 'string';
269 - if (isHostElement) {
270 - return false;
271 - }
272 - return true;
273 - };
274 -
275 - const markBegin = function(debugID, markType) {
276 - if (!shouldMark(debugID)) {
277 - return;
278 - }
279 -
280 - var markName = `${debugID}::${markType}`;
281 - lastMarkTimeStamp = performanceNow();
282 - performance.mark(markName);
283 - };
284 -
285 - const markEnd = function(debugID, markType) {
286 - if (!shouldMark(debugID)) {
287 - return;
288 - }
289 -
290 - var markName = `${debugID}::${markType}`;
291 - var displayName =
292 - ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown';
293 -
294 - // Chrome has an issue of dropping markers recorded too fast:
295 - // https://bugs.chromium.org/p/chromium/issues/detail?id=640652
296 - // To work around this, we will not report very small measurements.
297 - // I determined the magic number by tweaking it back and forth.
298 - // 0.05ms was enough to prevent the issue, but I set it to 0.1ms to be safe.
299 - // When the bug is fixed, we can `measure()` unconditionally if we want to.
300 - var timeStamp = performanceNow();
301 - if (timeStamp - lastMarkTimeStamp > 0.1) {
302 - var measurementName = `${displayName} [${markType}]`;
303 - performance.measure(measurementName, markName);
304 - }
305 -
306 - performance.clearMarks(markName);
307 - if (measurementName) {
308 - performance.clearMeasures(measurementName);
309 - }
310 - };
311 -
312 - ReactDebugTool = {
313 - addHook(hook: Hook): void {
314 - hooks.push(hook);
315 - },
316 - removeHook(hook: Hook): void {
317 - for (var i = 0; i < hooks.length; i++) {
318 - if (hooks[i] === hook) {
319 - hooks.splice(i, 1);
320 - i--;
321 - }
322 - }
323 - },
324 - isProfiling(): boolean {
325 - return isProfiling;
326 - },
327 - beginProfiling(): void {
328 - if (isProfiling) {
329 - return;
330 - }
331 -
332 - isProfiling = true;
333 - flushHistory.length = 0;
334 - resetMeasurements();
335 - ReactDebugTool.addHook(ReactHostOperationHistoryHook);
336 - },
337 - endProfiling(): void {
338 - if (!isProfiling) {
339 - return;
340 - }
341 -
342 - isProfiling = false;
343 - resetMeasurements();
344 - ReactDebugTool.removeHook(ReactHostOperationHistoryHook);
345 - },
346 - getFlushHistory(): FlushHistory {
347 - return flushHistory;
348 - },
349 - onBeginFlush(): void {
350 - currentFlushNesting++;
351 - resetMeasurements();
352 - pauseCurrentLifeCycleTimer();
353 - emitEvent('onBeginFlush');
354 - },
355 - onEndFlush(): void {
356 - resetMeasurements();
357 - currentFlushNesting--;
358 - resumeCurrentLifeCycleTimer();
359 - emitEvent('onEndFlush');
360 - },
361 - onBeginLifeCycleTimer(debugID: DebugID, timerType: TimerType): void {
362 - checkDebugID(debugID);
363 - emitEvent('onBeginLifeCycleTimer', debugID, timerType);
364 - markBegin(debugID, timerType);
365 - beginLifeCycleTimer(debugID, timerType);
366 - },
367 - onEndLifeCycleTimer(debugID: DebugID, timerType: TimerType): void {
368 - checkDebugID(debugID);
369 - endLifeCycleTimer(debugID, timerType);
370 - markEnd(debugID, timerType);
371 - emitEvent('onEndLifeCycleTimer', debugID, timerType);
372 - },
373 - onBeginProcessingChildContext(): void {
374 - emitEvent('onBeginProcessingChildContext');
375 - },
376 - onEndProcessingChildContext(): void {
377 - emitEvent('onEndProcessingChildContext');
378 - },
379 - onHostOperation(operation: Operation) {
380 - checkDebugID(operation.instanceID);
381 - emitEvent('onHostOperation', operation);
382 - },
383 - onSetState(): void {
384 - emitEvent('onSetState');
385 - },
386 - onSetChildren(debugID: DebugID, childDebugIDs: Array<DebugID>) {
387 - checkDebugID(debugID);
388 - childDebugIDs.forEach(checkDebugID);
389 - emitEvent('onSetChildren', debugID, childDebugIDs);
390 - },
391 - onBeforeMountComponent(
392 - debugID: DebugID,
393 - element: ReactElement,
394 - parentDebugID: DebugID,
395 - ): void {
396 - checkDebugID(debugID);
397 - checkDebugID(parentDebugID, true);
398 - emitEvent('onBeforeMountComponent', debugID, element, parentDebugID);
399 - markBegin(debugID, 'mount');
400 - },
401 - onMountComponent(debugID: DebugID): void {
402 - checkDebugID(debugID);
403 - markEnd(debugID, 'mount');
404 - emitEvent('onMountComponent', debugID);
405 - },
406 - onBeforeUpdateComponent(debugID: DebugID, element: ReactElement): void {
407 - checkDebugID(debugID);
408 - emitEvent('onBeforeUpdateComponent', debugID, element);
409 - markBegin(debugID, 'update');
410 - },
411 - onUpdateComponent(debugID: DebugID): void {
412 - checkDebugID(debugID);
413 - markEnd(debugID, 'update');
414 - emitEvent('onUpdateComponent', debugID);
415 - },
416 - onBeforeUnmountComponent(debugID: DebugID): void {
417 - checkDebugID(debugID);
418 - emitEvent('onBeforeUnmountComponent', debugID);
419 - markBegin(debugID, 'unmount');
420 - },
421 - onUnmountComponent(debugID: DebugID): void {
422 - checkDebugID(debugID);
423 - markEnd(debugID, 'unmount');
424 - emitEvent('onUnmountComponent', debugID);
425 - },
426 - onTestEvent(): void {
427 - emitEvent('onTestEvent');
428 - },
429 - };
430 -
431 - ReactDebugTool.addHook(ReactInvalidSetStateWarningHook);
432 - ReactDebugTool.addHook(ReactComponentTreeHook);
433 - var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
434 - if (/[?&]react_perf\b/.test(url)) {
435 - ReactDebugTool.beginProfiling();
436 - }
437 -}
438 -
439 -module.exports = ReactDebugTool;
src/renderers/shared/ReactGlobalSharedState.js
-1
@@ -18,7 +18,6 @@ var ReactGlobalSharedState = {
18
19 if (__DEV__) {
20 Object.assign(ReactGlobalSharedState, {
21 - ReactComponentTreeHook: ReactInternals.ReactComponentTreeHook,
21 ReactDebugCurrentFrame: ReactInternals.ReactDebugCurrentFrame,
22 });
23 }
src/renderers/shared/ReactInstrumentation.js deleted
-21
@@ -1,21 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @providesModule ReactInstrumentation
8 - * @flow
9 - */
10 -
11 -'use strict';
12 -
13 -// Trust the developer to only use ReactInstrumentation with a __DEV__ check
14 -var debugTool = ((null: any): typeof ReactDebugTool);
15 -
16 -if (__DEV__) {
17 - var ReactDebugTool = require('ReactDebugTool');
18 - debugTool = ReactDebugTool;
19 -}
20 -
21 -module.exports = {debugTool};
src/renderers/shared/ReactPerf.js deleted
-456
@@ -1,456 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @providesModule ReactPerf
8 - * @flow
9 - */
10 -
11 -'use strict';
12 -
13 -var ReactDebugTool = require('ReactDebugTool');
14 -var lowPriorityWarning = require('lowPriorityWarning');
15 -var alreadyWarned = false;
16 -
17 -import type {FlushHistory} from 'ReactDebugTool';
18 -
19 -function roundFloat(val, base = 2) {
20 - var n = Math.pow(10, base);
21 - return Math.floor(val * n) / n;
22 -}
23 -
24 -// Flow type definition of console.table is too strict right now, see
25 -// https://github.com/facebook/flow/pull/2353 for updates
26 -function consoleTable(table: Array<{[key: string]: any}>): void {
27 - console.table((table: any));
28 -}
29 -
30 -function warnInProduction() {
31 - if (alreadyWarned) {
32 - return;
33 - }
34 - alreadyWarned = true;
35 - if (typeof console !== 'undefined') {
36 - console.error(
37 - 'ReactPerf is not supported in the production builds of React. ' +
38 - 'To collect measurements, please use the development build of React instead.',
39 - );
40 - }
41 -}
42 -
43 -function getLastMeasurements() {
44 - if (!__DEV__) {
45 - warnInProduction();
46 - return [];
47 - }
48 -
49 - return ReactDebugTool.getFlushHistory();
50 -}
51 -
52 -function getExclusive(flushHistory = getLastMeasurements()) {
53 - if (!__DEV__) {
54 - warnInProduction();
55 - return [];
56 - }
57 -
58 - var aggregatedStats = {};
59 - var affectedIDs = {};
60 -
61 - function updateAggregatedStats(
62 - treeSnapshot,
63 - instanceID,
64 - timerType,
65 - applyUpdate,
66 - ) {
67 - var {displayName} = treeSnapshot[instanceID];
68 - var key = displayName;
69 - var stats = aggregatedStats[key];
70 - if (!stats) {
71 - affectedIDs[key] = {};
72 - stats = aggregatedStats[key] = {
73 - key,
74 - instanceCount: 0,
75 - counts: {},
76 - durations: {},
77 - totalDuration: 0,
78 - };
79 - }
80 - if (!stats.durations[timerType]) {
81 - stats.durations[timerType] = 0;
82 - }
83 - if (!stats.counts[timerType]) {
84 - stats.counts[timerType] = 0;
85 - }
86 - affectedIDs[key][instanceID] = true;
87 - applyUpdate(stats);
88 - }
89 -
90 - flushHistory.forEach(flush => {
91 - var {measurements, treeSnapshot} = flush;
92 - measurements.forEach(measurement => {
93 - var {duration, instanceID, timerType} = measurement;
94 - updateAggregatedStats(treeSnapshot, instanceID, timerType, stats => {
95 - stats.totalDuration += duration;
96 - stats.durations[timerType] += duration;
97 - stats.counts[timerType]++;
98 - });
99 - });
100 - });
101 -
102 - return Object.keys(aggregatedStats)
103 - .map(key => ({
104 - ...aggregatedStats[key],
105 - instanceCount: Object.keys(affectedIDs[key]).length,
106 - }))
107 - .sort((a, b) => b.totalDuration - a.totalDuration);
108 -}
109 -
110 -function getInclusive(flushHistory = getLastMeasurements()) {
111 - if (!__DEV__) {
112 - warnInProduction();
113 - return [];
114 - }
115 -
116 - var aggregatedStats = {};
117 - var affectedIDs = {};
118 -
119 - function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
120 - var {displayName, ownerID} = treeSnapshot[instanceID];
121 - var owner = treeSnapshot[ownerID];
122 - var key = (owner ? owner.displayName + ' > ' : '') + displayName;
123 - var stats = aggregatedStats[key];
124 - if (!stats) {
125 - affectedIDs[key] = {};
126 - stats = aggregatedStats[key] = {
127 - key,
128 - instanceCount: 0,
129 - inclusiveRenderDuration: 0,
130 - renderCount: 0,
131 - };
132 - }
133 - affectedIDs[key][instanceID] = true;
134 - applyUpdate(stats);
135 - }
136 -
137 - var isCompositeByID = {};
138 - flushHistory.forEach(flush => {
139 - var {measurements} = flush;
140 - measurements.forEach(measurement => {
141 - var {instanceID, timerType} = measurement;
142 - if (timerType !== 'render') {
143 - return;
144 - }
145 - isCompositeByID[instanceID] = true;
146 - });
147 - });
148 -
149 - flushHistory.forEach(flush => {
150 - var {measurements, treeSnapshot} = flush;
151 - measurements.forEach(measurement => {
152 - var {duration, instanceID, timerType} = measurement;
153 - if (timerType !== 'render') {
154 - return;
155 - }
156 - updateAggregatedStats(treeSnapshot, instanceID, stats => {
157 - stats.renderCount++;
158 - });
159 - var nextParentID = instanceID;
160 - while (nextParentID) {
161 - // As we traverse parents, only count inclusive time towards composites.
162 - // We know something is a composite if its render() was called.
163 - if (isCompositeByID[nextParentID]) {
164 - updateAggregatedStats(treeSnapshot, nextParentID, stats => {
165 - stats.inclusiveRenderDuration += duration;
166 - });
167 - }
168 - nextParentID = treeSnapshot[nextParentID].parentID;
169 - }
170 - });
171 - });
172 -
173 - return Object.keys(aggregatedStats)
174 - .map(key => ({
175 - ...aggregatedStats[key],
176 - instanceCount: Object.keys(affectedIDs[key]).length,
177 - }))
178 - .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
179 -}
180 -
181 -function getWasted(flushHistory = getLastMeasurements()) {
182 - if (!__DEV__) {
183 - warnInProduction();
184 - return [];
185 - }
186 -
187 - var aggregatedStats = {};
188 - var affectedIDs = {};
189 -
190 - function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
191 - var {displayName, ownerID} = treeSnapshot[instanceID];
192 - var owner = treeSnapshot[ownerID];
193 - var key = (owner ? owner.displayName + ' > ' : '') + displayName;
194 - var stats = aggregatedStats[key];
195 - if (!stats) {
196 - affectedIDs[key] = {};
197 - stats = aggregatedStats[key] = {
198 - key,
199 - instanceCount: 0,
200 - inclusiveRenderDuration: 0,
201 - renderCount: 0,
202 - };
203 - }
204 - affectedIDs[key][instanceID] = true;
205 - applyUpdate(stats);
206 - }
207 -
208 - flushHistory.forEach(flush => {
209 - var {measurements, treeSnapshot, operations} = flush;
210 - var isDefinitelyNotWastedByID = {};
211 -
212 - // Find host components associated with an operation in this batch.
213 - // Mark all components in their parent tree as definitely not wasted.
214 - operations.forEach(operation => {
215 - var {instanceID} = operation;
216 - var nextParentID = instanceID;
217 - while (nextParentID) {
218 - isDefinitelyNotWastedByID[nextParentID] = true;
219 - nextParentID = treeSnapshot[nextParentID].parentID;
220 - }
221 - });
222 -
223 - // Find composite components that rendered in this batch.
224 - // These are potential candidates for being wasted renders.
225 - var renderedCompositeIDs = {};
226 - measurements.forEach(measurement => {
227 - var {instanceID, timerType} = measurement;
228 - if (timerType !== 'render') {
229 - return;
230 - }
231 - renderedCompositeIDs[instanceID] = true;
232 - });
233 -
234 - measurements.forEach(measurement => {
235 - var {duration, instanceID, timerType} = measurement;
236 - if (timerType !== 'render') {
237 - return;
238 - }
239 -
240 - // If there was a DOM update below this component, or it has just been
241 - // mounted, its render() is not considered wasted.
242 - var {updateCount} = treeSnapshot[instanceID];
243 - if (isDefinitelyNotWastedByID[instanceID] || updateCount === 0) {
244 - return;
245 - }
246 -
247 - // We consider this render() wasted.
248 - updateAggregatedStats(treeSnapshot, instanceID, stats => {
249 - stats.renderCount++;
250 - });
251 -
252 - var nextParentID = instanceID;
253 - while (nextParentID) {
254 - // Any parents rendered during this batch are considered wasted
255 - // unless we previously marked them as dirty.
256 - var isWasted =
257 - renderedCompositeIDs[nextParentID] &&
258 - !isDefinitelyNotWastedByID[nextParentID];
259 - if (isWasted) {
260 - updateAggregatedStats(treeSnapshot, nextParentID, stats => {
261 - stats.inclusiveRenderDuration += duration;
262 - });
263 - }
264 - nextParentID = treeSnapshot[nextParentID].parentID;
265 - }
266 - });
267 - });
268 -
269 - return Object.keys(aggregatedStats)
270 - .map(key => ({
271 - ...aggregatedStats[key],
272 - instanceCount: Object.keys(affectedIDs[key]).length,
273 - }))
274 - .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
275 -}
276 -
277 -function getOperations(flushHistory = getLastMeasurements()) {
278 - if (!__DEV__) {
279 - warnInProduction();
280 - return [];
281 - }
282 -
283 - var stats = [];
284 - flushHistory.forEach((flush, flushIndex) => {
285 - var {operations, treeSnapshot} = flush;
286 - operations.forEach(operation => {
287 - var {instanceID, type, payload} = operation;
288 - var {displayName, ownerID} = treeSnapshot[instanceID];
289 - var owner = treeSnapshot[ownerID];
290 - var key = (owner ? owner.displayName + ' > ' : '') + displayName;
291 -
292 - stats.push({
293 - flushIndex,
294 - instanceID,
295 - key,
296 - type,
297 - ownerID,
298 - payload,
299 - });
300 - });
301 - });
302 - return stats;
303 -}
304 -
305 -function printExclusive(flushHistory?: FlushHistory) {
306 - if (!__DEV__) {
307 - warnInProduction();
308 - return;
309 - }
310 -
311 - var stats = getExclusive(flushHistory);
312 - var table = stats.map(item => {
313 - var {key, instanceCount, totalDuration} = item;
314 - var renderCount = item.counts.render || 0;
315 - var renderDuration = item.durations.render || 0;
316 - return {
317 - Component: key,
318 - 'Total time (ms)': roundFloat(totalDuration),
319 - 'Instance count': instanceCount,
320 - 'Total render time (ms)': roundFloat(renderDuration),
321 - 'Average render time (ms)': renderCount
322 - ? roundFloat(renderDuration / renderCount)
323 - : undefined,
324 - 'Render count': renderCount,
325 - 'Total lifecycle time (ms)': roundFloat(totalDuration - renderDuration),
326 - };
327 - });
328 - consoleTable(table);
329 -}
330 -
331 -function printInclusive(flushHistory?: FlushHistory) {
332 - if (!__DEV__) {
333 - warnInProduction();
334 - return;
335 - }
336 -
337 - var stats = getInclusive(flushHistory);
338 - var table = stats.map(item => {
339 - var {key, instanceCount, inclusiveRenderDuration, renderCount} = item;
340 - return {
341 - 'Owner > Component': key,
342 - 'Inclusive render time (ms)': roundFloat(inclusiveRenderDuration),
343 - 'Instance count': instanceCount,
344 - 'Render count': renderCount,
345 - };
346 - });
347 - consoleTable(table);
348 -}
349 -
350 -function printWasted(flushHistory?: FlushHistory) {
351 - if (!__DEV__) {
352 - warnInProduction();
353 - return;
354 - }
355 -
356 - var stats = getWasted(flushHistory);
357 - var table = stats.map(item => {
358 - var {key, instanceCount, inclusiveRenderDuration, renderCount} = item;
359 - return {
360 - 'Owner > Component': key,
361 - 'Inclusive wasted time (ms)': roundFloat(inclusiveRenderDuration),
362 - 'Instance count': instanceCount,
363 - 'Render count': renderCount,
364 - };
365 - });
366 - consoleTable(table);
367 -}
368 -
369 -function printOperations(flushHistory?: FlushHistory) {
370 - if (!__DEV__) {
371 - warnInProduction();
372 - return;
373 - }
374 -
375 - var stats = getOperations(flushHistory);
376 - var table = stats.map(stat => ({
377 - 'Owner > Node': stat.key,
378 - Operation: stat.type,
379 - Payload: typeof stat.payload === 'object'
380 - ? JSON.stringify(stat.payload)
381 - : stat.payload,
382 - 'Flush index': stat.flushIndex,
383 - 'Owner Component ID': stat.ownerID,
384 - 'DOM Component ID': stat.instanceID,
385 - }));
386 - consoleTable(table);
387 -}
388 -
389 -var warnedAboutPrintDOM = false;
390 -function printDOM(measurements: FlushHistory) {
391 - lowPriorityWarning(
392 - warnedAboutPrintDOM,
393 - '`ReactPerf.printDOM(...)` is deprecated. Use ' +
394 - '`ReactPerf.printOperations(...)` instead.',
395 - );
396 - warnedAboutPrintDOM = true;
397 - return printOperations(measurements);
398 -}
399 -
400 -var warnedAboutGetMeasurementsSummaryMap = false;
401 -function getMeasurementsSummaryMap(measurements: FlushHistory) {
402 - lowPriorityWarning(
403 - warnedAboutGetMeasurementsSummaryMap,
404 - '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
405 - '`ReactPerf.getWasted(...)` instead.',
406 - );
407 - warnedAboutGetMeasurementsSummaryMap = true;
408 - return getWasted(measurements);
409 -}
410 -
411 -function start() {
412 - if (!__DEV__) {
413 - warnInProduction();
414 - return;
415 - }
416 -
417 - ReactDebugTool.beginProfiling();
418 -}
419 -
420 -function stop() {
421 - if (!__DEV__) {
422 - warnInProduction();
423 - return;
424 - }
425 -
426 - ReactDebugTool.endProfiling();
427 -}
428 -
429 -function isRunning() {
430 - if (!__DEV__) {
431 - warnInProduction();
432 - return false;
433 - }
434 -
435 - return ReactDebugTool.isProfiling();
436 -}
437 -
438 -var ReactPerfAnalysis = {
439 - getLastMeasurements,
440 - getExclusive,
441 - getInclusive,
442 - getWasted,
443 - getOperations,
444 - printExclusive,
445 - printInclusive,
446 - printWasted,
447 - printOperations,
448 - start,
449 - stop,
450 - isRunning,
451 - // Deprecated:
452 - printDOM,
453 - getMeasurementsSummaryMap,
454 -};
455 -
456 -module.exports = ReactPerfAnalysis;
src/renderers/shared/__tests__/ReactDebugTool-test.js deleted
-82
@@ -1,82 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -describe('ReactDebugTool', () => {
13 - var ReactDebugTool;
14 -
15 - beforeEach(() => {
16 - jest.resetModules();
17 - ReactDebugTool = require('ReactDebugTool');
18 - });
19 -
20 - it('should add and remove hooks', () => {
21 - var handler1 = jasmine.createSpy('spy');
22 - var handler2 = jasmine.createSpy('spy');
23 - var hook1 = {onTestEvent: handler1};
24 - var hook2 = {onTestEvent: handler2};
25 -
26 - ReactDebugTool.addHook(hook1);
27 - ReactDebugTool.onTestEvent();
28 - expect(handler1.calls.count()).toBe(1);
29 - expect(handler2.calls.count()).toBe(0);
30 -
31 - ReactDebugTool.onTestEvent();
32 - expect(handler1.calls.count()).toBe(2);
33 - expect(handler2.calls.count()).toBe(0);
34 -
35 - ReactDebugTool.addHook(hook2);
36 - ReactDebugTool.onTestEvent();
37 - expect(handler1.calls.count()).toBe(3);
38 - expect(handler2.calls.count()).toBe(1);
39 -
40 - ReactDebugTool.onTestEvent();
41 - expect(handler1.calls.count()).toBe(4);
42 - expect(handler2.calls.count()).toBe(2);
43 -
44 - ReactDebugTool.removeHook(hook1);
45 - ReactDebugTool.onTestEvent();
46 - expect(handler1.calls.count()).toBe(4);
47 - expect(handler2.calls.count()).toBe(3);
48 -
49 - ReactDebugTool.removeHook(hook2);
50 - ReactDebugTool.onTestEvent();
51 - expect(handler1.calls.count()).toBe(4);
52 - expect(handler2.calls.count()).toBe(3);
53 - });
54 -
55 - it('warns once when an error is thrown in hook', () => {
56 - spyOn(console, 'error');
57 - ReactDebugTool.addHook({
58 - onTestEvent() {
59 - throw new Error('Hi.');
60 - },
61 - });
62 -
63 - ReactDebugTool.onTestEvent();
64 - expectDev(console.error.calls.count()).toBe(1);
65 - expectDev(console.error.calls.argsFor(0)[0]).toContain(
66 - 'Exception thrown by hook while handling ' + 'onTestEvent: Error: Hi.',
67 - );
68 -
69 - ReactDebugTool.onTestEvent();
70 - expectDev(console.error.calls.count()).toBe(1);
71 - });
72 -
73 - it('returns isProfiling state', () => {
74 - expect(ReactDebugTool.isProfiling()).toBe(false);
75 -
76 - ReactDebugTool.beginProfiling();
77 - expect(ReactDebugTool.isProfiling()).toBe(true);
78 -
79 - ReactDebugTool.endProfiling();
80 - expect(ReactDebugTool.isProfiling()).toBe(false);
81 - });
82 -});
src/test/ReactComponentTreeTestUtils.js deleted
-105
@@ -1,105 +0,0 @@
1 -/**
2 - * Copyright (c) 2016-present, Facebook, Inc.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @providesModule ReactComponentTreeTestUtils
8 - */
9 -
10 -'use strict';
11 -
12 -var ReactComponentTreeHook = require('ReactComponentTreeHook');
13 -
14 -function getRootDisplayNames() {
15 - return ReactComponentTreeHook.getRootIDs().map(
16 - ReactComponentTreeHook.getDisplayName,
17 - );
18 -}
19 -
20 -function getRegisteredDisplayNames() {
21 - return ReactComponentTreeHook.getRegisteredIDs().map(
22 - ReactComponentTreeHook.getDisplayName,
23 - );
24 -}
25 -
26 -function expectTree(rootID, expectedTree, parentPath) {
27 - var displayName = ReactComponentTreeHook.getDisplayName(rootID);
28 - var ownerID = ReactComponentTreeHook.getOwnerID(rootID);
29 - var parentID = ReactComponentTreeHook.getParentID(rootID);
30 - var childIDs = ReactComponentTreeHook.getChildIDs(rootID);
31 - var text = ReactComponentTreeHook.getText(rootID);
32 - var element = ReactComponentTreeHook.getElement(rootID);
33 - var path = parentPath ? `${parentPath} > ${displayName}` : displayName;
34 -
35 - function expectEqual(actual, expected, name) {
36 - // Get Jasmine to print descriptive error messages.
37 - // We pass path so that we know where the mismatch occurred.
38 - expectDev({
39 - path,
40 - [name]: actual,
41 - }).toEqual({
42 - path,
43 - [name]: expected,
44 - });
45 - }
46 -
47 - if (expectedTree.parentDisplayName !== undefined) {
48 - expectEqual(
49 - ReactComponentTreeHook.getDisplayName(parentID),
50 - expectedTree.parentDisplayName,
51 - 'parentDisplayName',
52 - );
53 - }
54 - if (expectedTree.ownerDisplayName !== undefined) {
55 - expectEqual(
56 - ReactComponentTreeHook.getDisplayName(ownerID),
57 - expectedTree.ownerDisplayName,
58 - 'ownerDisplayName',
59 - );
60 - }
61 - if (expectedTree.parentID !== undefined) {
62 - expectEqual(parentID, expectedTree.parentID, 'parentID');
63 - }
64 - if (expectedTree.text !== undefined) {
65 - expectEqual(text, expectedTree.text, 'text');
66 - expectEqual('' + element, expectedTree.text, 'element.toString()');
67 - } else {
68 - expectEqual(text, null, 'text');
69 - }
70 - if (expectedTree.element !== undefined) {
71 - // TODO: Comparing elements makes tests run out of memory on errors.
72 - // For now, compare just types.
73 - expectEqual(
74 - element && element.type,
75 - expectedTree.element && expectedTree.element.type,
76 - 'element.type',
77 - );
78 - } else if (text == null) {
79 - expectEqual(typeof element, 'object', 'typeof element');
80 - }
81 - if (expectedTree.children !== undefined) {
82 - expectEqual(
83 - childIDs.length,
84 - expectedTree.children.length,
85 - 'children.length',
86 - );
87 - for (var i = 0; i < childIDs.length; i++) {
88 - expectTree(
89 - childIDs[i],
90 - {parentID: rootID, ...expectedTree.children[i]},
91 - path,
92 - );
93 - }
94 - } else {
95 - expectEqual(childIDs, [], 'childIDs');
96 - }
97 -}
98 -
99 -var ReactComponentTreeTestUtils = {
100 - expectTree,
101 - getRootDisplayNames,
102 - getRegisteredDisplayNames,
103 -};
104 -
105 -module.exports = ReactComponentTreeTestUtils;