@samitouri / QOS-React-2 / commits / b7f6a642f6

Make ReactComponentTreeDevtool work with React Native

Dan Abramov committed Apr 27, 2016 at 22:12 UTC b7f6a642f61c3071b77288309548cdedab431b3b
6 files changed +1754 -2
src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.js
+4 -2
@@ -93,6 +93,8 @@ describe('ReactComponentTreeDevtool', () => {
93 return getTree(rootInstance._debugID, options).children[0];
94 }
95
96 + // Mount once, render updates, then unmount.
97 + // Ensure the tree is correct on every step.
98 pairs.forEach(([element, expectedTree]) => {
99 currentElement = element;
100 ReactDOM.render(<Wrapper />, node);
@@ -101,17 +103,17 @@ describe('ReactComponentTreeDevtool', () => {
103 expect(getActualTree()).toEqual(expectedTree);
104 });
105 ReactDOM.unmountComponentAtNode(node);
104 -
106 ReactComponentTreeDevtool.purgeUnmountedComponents();
107 expect(getActualTree()).toBe(undefined);
108 expect(getRootDisplayNames()).toEqual([]);
109 expect(getRegisteredDisplayNames()).toEqual([]);
110
111 + // Server render every pair.
112 + // Ensure the tree is correct on every step.
113 pairs.forEach(([element, expectedTree]) => {
114 currentElement = element;
115 ReactDOMServer.renderToString(<Wrapper />);
116 expect(getActualTree()).toEqual(expectedTree);
114 -
117 ReactComponentTreeDevtool.purgeUnmountedComponents();
118 expect(getActualTree()).toBe(undefined);
119 expect(getRootDisplayNames()).toEqual([]);
src/isomorphic/devtools/__tests__/ReactComponentTreeDevtool-test.native.js new
+1705
@@ -0,0 +1,1705 @@
1 +/**
2 + * Copyright 2016-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +'use strict';
13 +
14 +describe('ReactComponentTreeDevtool', () => {
15 + var React;
16 + var ReactNative;
17 + var ReactInstanceMap;
18 + var ReactComponentTreeDevtool;
19 + var createReactNativeComponentClass;
20 + var View;
21 + var Image;
22 + var Text;
23 +
24 + beforeEach(() => {
25 + jest.resetModuleRegistry();
26 +
27 + React = require('React');
28 + ReactNative = require('ReactNative');
29 + ReactInstanceMap = require('ReactInstanceMap');
30 + ReactComponentTreeDevtool = require('ReactComponentTreeDevtool');
31 + View = require('View');
32 + createReactNativeComponentClass = require('createReactNativeComponentClass');
33 + Image = createReactNativeComponentClass({
34 + validAttributes: {},
35 + uiViewClassName: 'Image',
36 + });
37 + var RCText = createReactNativeComponentClass({
38 + validAttributes: {},
39 + uiViewClassName: 'RCText',
40 + });
41 + Text = React.createClass({
42 + childContextTypes: {
43 + isInAParentText: React.PropTypes.bool,
44 + },
45 + getChildContext() {
46 + return {isInAParentText: true};
47 + },
48 + render() {
49 + return <RCText {...this.props} />;
50 + },
51 + });
52 + });
53 +
54 + function getRootDisplayNames() {
55 + return ReactComponentTreeDevtool.getRootIDs()
56 + .map(ReactComponentTreeDevtool.getDisplayName);
57 + }
58 +
59 + function getRegisteredDisplayNames() {
60 + return ReactComponentTreeDevtool.getRegisteredIDs()
61 + .map(ReactComponentTreeDevtool.getDisplayName);
62 + }
63 +
64 + function getTree(rootID, options = {}) {
65 + var {
66 + includeOwnerDisplayName = false,
67 + includeParentDisplayName = false,
68 + expectedParentID = null,
69 + } = options;
70 +
71 + var result = {
72 + displayName: ReactComponentTreeDevtool.getDisplayName(rootID),
73 + };
74 +
75 + var ownerID = ReactComponentTreeDevtool.getOwnerID(rootID);
76 + var parentID = ReactComponentTreeDevtool.getParentID(rootID);
77 + expect(parentID).toBe(expectedParentID);
78 +
79 + if (includeParentDisplayName && parentID) {
80 + result.parentDisplayName = ReactComponentTreeDevtool.getDisplayName(parentID);
81 + }
82 + if (includeOwnerDisplayName && ownerID) {
83 + result.ownerDisplayName = ReactComponentTreeDevtool.getDisplayName(ownerID);
84 + }
85 +
86 + var childIDs = ReactComponentTreeDevtool.getChildIDs(rootID);
87 + var text = ReactComponentTreeDevtool.getText(rootID);
88 + if (text != null) {
89 + result.text = text;
90 + } else {
91 + result.children = childIDs.map(childID =>
92 + getTree(childID, {...options, expectedParentID: rootID })
93 + );
94 + }
95 +
96 + return result;
97 + }
98 +
99 + function assertTreeMatches(pairs, options) {
100 + if (!Array.isArray(pairs[0])) {
101 + pairs = [pairs];
102 + }
103 +
104 + var currentElement;
105 + var rootInstance;
106 +
107 + class Wrapper extends React.Component {
108 + render() {
109 + rootInstance = ReactInstanceMap.get(this);
110 + return currentElement;
111 + }
112 + }
113 +
114 + function getActualTree() {
115 + return getTree(rootInstance._debugID, options).children[0];
116 + }
117 +
118 + // Mount once, render updates, then unmount.
119 + // Ensure the tree is correct on every step.
120 + pairs.forEach(([element, expectedTree]) => {
121 + currentElement = element;
122 + ReactNative.render(<Wrapper />, 1);
123 + expect(getActualTree()).toEqual(expectedTree);
124 + ReactComponentTreeDevtool.purgeUnmountedComponents();
125 + expect(getActualTree()).toEqual(expectedTree);
126 + });
127 + ReactNative.unmountComponentAtNode(1);
128 + ReactComponentTreeDevtool.purgeUnmountedComponents();
129 + expect(getActualTree()).toBe(undefined);
130 + expect(getRootDisplayNames()).toEqual([]);
131 + expect(getRegisteredDisplayNames()).toEqual([]);
132 +
133 + // Mount and unmount for every pair.
134 + // Ensure the tree is correct on every step.
135 + pairs.forEach(([element, expectedTree]) => {
136 + currentElement = element;
137 + ReactNative.render(<Wrapper />, 1);
138 + ReactNative.unmountComponentAtNode(1);
139 + expect(getActualTree()).toEqual(expectedTree);
140 + ReactComponentTreeDevtool.purgeUnmountedComponents();
141 + expect(getActualTree()).toBe(undefined);
142 + expect(getRootDisplayNames()).toEqual([]);
143 + expect(getRegisteredDisplayNames()).toEqual([]);
144 + });
145 + }
146 +
147 + describe('mount', () => {
148 + it('uses displayName or Unknown for classic components', () => {
149 + var Foo = React.createClass({
150 + render() {
151 + return null;
152 + },
153 + });
154 + Foo.displayName = 'Bar';
155 + var Baz = React.createClass({
156 + render() {
157 + return null;
158 + },
159 + });
160 + var Qux = React.createClass({
161 + render() {
162 + return null;
163 + },
164 + });
165 + delete Qux.displayName;
166 +
167 + var element = <View><Foo /><Baz /><Qux /></View>;
168 + var tree = {
169 + displayName: 'View',
170 + children: [{
171 + displayName: 'Bar',
172 + children: [],
173 + }, {
174 + displayName: 'Baz',
175 + children: [],
176 + }, {
177 + displayName: 'Unknown',
178 + children: [],
179 + }],
180 + };
181 + assertTreeMatches([element, tree]);
182 + });
183 +
184 + it('uses displayName, name, or ReactComponent for modern components', () => {
185 + class Foo extends React.Component {
186 + render() {
187 + return null;
188 + }
189 + }
190 + Foo.displayName = 'Bar';
191 + class Baz extends React.Component {
192 + render() {
193 + return null;
194 + }
195 + }
196 + class Qux extends React.Component {
197 + render() {
198 + return null;
199 + }
200 + }
201 + delete Qux.name;
202 +
203 + var element = <View><Foo /><Baz /><Qux /></View>;
204 + var tree = {
205 + displayName: 'View',
206 + children: [{
207 + displayName: 'Bar',
208 + children: [],
209 + }, {
210 + displayName: 'Baz',
211 + children: [],
212 + }, {
213 + // Note: Ideally fallback name should be consistent (e.g. "Unknown")
214 + displayName: 'ReactComponent',
215 + children: [],
216 + }],
217 + };
218 + assertTreeMatches([element, tree]);
219 + });
220 +
221 + it('uses displayName, name, or Object for factory components', () => {
222 + function Foo() {
223 + return {
224 + render() {
225 + return null;
226 + },
227 + };
228 + }
229 + Foo.displayName = 'Bar';
230 + function Baz() {
231 + return {
232 + render() {
233 + return null;
234 + },
235 + };
236 + }
237 + function Qux() {
238 + return {
239 + render() {
240 + return null;
241 + },
242 + };
243 + }
244 + delete Qux.name;
245 +
246 + var element = <View><Foo /><Baz /><Qux /></View>;
247 + var tree = {
248 + displayName: 'View',
249 + children: [{
250 + displayName: 'Bar',
251 + children: [],
252 + }, {
253 + displayName: 'Baz',
254 + children: [],
255 + }, {
256 + displayName: 'Unknown',
257 + children: [],
258 + }],
259 + };
260 + assertTreeMatches([element, tree]);
261 + });
262 +
263 + it('uses displayName, name, or StatelessComponent for functional components', () => {
264 + function Foo() {
265 + return null;
266 + }
267 + Foo.displayName = 'Bar';
268 + function Baz() {
269 + return null;
270 + }
271 + function Qux() {
272 + return null;
273 + }
274 + delete Qux.name;
275 +
276 + var element = <View><Foo /><Baz /><Qux /></View>;
277 + var tree = {
278 + displayName: 'View',
279 + children: [{
280 + displayName: 'Bar',
281 + children: [],
282 + }, {
283 + displayName: 'Baz',
284 + children: [],
285 + }, {
286 + displayName: 'Unknown',
287 + children: [],
288 + }],
289 + };
290 + assertTreeMatches([element, tree]);
291 + });
292 +
293 + it('reports a native tree correctly', () => {
294 + var element = (
295 + <View>
296 + <View>
297 + <Text>
298 + Hi!
299 + </Text>
300 + </View>
301 + <Image />
302 + </View>
303 + );
304 + var tree = {
305 + displayName: 'View',
306 + children: [{
307 + displayName: 'View',
308 + children: [{
309 + displayName: 'Text',
310 + children: [{
311 + displayName: 'RCText',
312 + children: [{
313 + displayName: '#text',
314 + text: 'Hi!',
315 + }],
316 + }],
317 + }],
318 + }, {
319 + displayName: 'Image',
320 + children: [],
321 + }],
322 + };
323 + assertTreeMatches([element, tree]);
324 + });
325 +
326 + it('reports a simple tree with composites correctly', () => {
327 + class Foo extends React.Component {
328 + render() {
329 + return <Image />;
330 + }
331 + }
332 +
333 + var element = <Foo />;
334 + var tree = {
335 + displayName: 'Foo',
336 + children: [{
337 + displayName: 'Image',
338 + children: [],
339 + }],
340 + };
341 + assertTreeMatches([element, tree]);
342 + });
343 +
344 + it('reports a tree with composites correctly', () => {
345 + var Qux = React.createClass({
346 + render() {
347 + return null;
348 + },
349 + });
350 + function Foo() {
351 + return {
352 + render() {
353 + return <Qux />;
354 + },
355 + };
356 + }
357 + function Bar({children}) {
358 + return <View>{children}</View>;
359 + }
360 + class Baz extends React.Component {
361 + render() {
362 + return (
363 + <View>
364 + <Foo />
365 + <Bar>
366 + <Text>Hi,</Text>
367 + </Bar>
368 + <Image />
369 + </View>
370 + );
371 + }
372 + }
373 +
374 + var element = <Baz />;
375 + var tree = {
376 + displayName: 'Baz',
377 + children: [{
378 + displayName: 'View',
379 + children: [{
380 + displayName: 'Foo',
381 + children: [{
382 + displayName: 'Qux',
383 + children: [],
384 + }],
385 + }, {
386 + displayName: 'Bar',
387 + children: [{
388 + displayName: 'View',
389 + children: [{
390 + displayName: 'Text',
391 + children: [{
392 + displayName: 'RCText',
393 + children: [{
394 + displayName: '#text',
395 + text: 'Hi,',
396 + }],
397 + }],
398 + }],
399 + }],
400 + }, {
401 + displayName: 'Image',
402 + children: [],
403 + }],
404 + }],
405 + };
406 + assertTreeMatches([element, tree]);
407 + });
408 +
409 + it('ignores null children', () => {
410 + class Foo extends React.Component {
411 + render() {
412 + return null;
413 + }
414 + }
415 + var element = <Foo />;
416 + var tree = {
417 + displayName: 'Foo',
418 + children: [],
419 + };
420 + assertTreeMatches([element, tree]);
421 + });
422 +
423 + it('ignores false children', () => {
424 + class Foo extends React.Component {
425 + render() {
426 + return false;
427 + }
428 + }
429 + var element = <Foo />;
430 + var tree = {
431 + displayName: 'Foo',
432 + children: [],
433 + };
434 + assertTreeMatches([element, tree]);
435 + });
436 +
437 + it('reports text nodes as children', () => {
438 + var element = <Text>{'1'}{2}</Text>;
439 + var tree = {
440 + displayName: 'Text',
441 + children: [{
442 + displayName: 'RCText',
443 + children: [{
444 + displayName: '#text',
445 + text: '1',
446 + }, {
447 + displayName: '#text',
448 + text: '2',
449 + }],
450 + }],
451 + };
452 + assertTreeMatches([element, tree]);
453 + });
454 +
455 + it('reports a single text node as a child', () => {
456 + var element = <Text>{'1'}</Text>;
457 + var tree = {
458 + displayName: 'Text',
459 + children: [{
460 + displayName: 'RCText',
461 + children: [{
462 + displayName: '#text',
463 + text: '1',
464 + }],
465 + }],
466 + };
467 + assertTreeMatches([element, tree]);
468 + });
469 +
470 + it('reports a single number node as a child', () => {
471 + var element = <Text>{42}</Text>;
472 + var tree = {
473 + displayName: 'Text',
474 + children: [{
475 + displayName: 'RCText',
476 + children: [{
477 + displayName: '#text',
478 + text: '42',
479 + }],
480 + }],
481 + };
482 + assertTreeMatches([element, tree]);
483 + });
484 +
485 + it('reports a zero as a child', () => {
486 + var element = <Text>{0}</Text>;
487 + var tree = {
488 + displayName: 'Text',
489 + children: [{
490 + displayName: 'RCText',
491 + children: [{
492 + displayName: '#text',
493 + text: '0',
494 + }],
495 + }],
496 + };
497 + assertTreeMatches([element, tree]);
498 + });
499 +
500 + it('skips empty nodes for multiple children', () => {
501 + function Foo() {
502 + return <Image />;
503 + }
504 + var element = (
505 + <View>
506 + {false}
507 + <Foo />
508 + {null}
509 + <Foo />
510 + </View>
511 + );
512 + var tree = {
513 + displayName: 'View',
514 + children: [{
515 + displayName: 'Foo',
516 + children: [{
517 + displayName: 'Image',
518 + children: [],
519 + }],
520 + }, {
521 + displayName: 'Foo',
522 + children: [{
523 + displayName: 'Image',
524 + children: [],
525 + }],
526 + }],
527 + };
528 + assertTreeMatches([element, tree]);
529 + });
530 + });
531 +
532 + describe('update', () => {
533 + describe('native component', () => {
534 + it('updates text of a single text child', () => {
535 + var elementBefore = <Text>Hi.</Text>;
536 + var treeBefore = {
537 + displayName: 'Text',
538 + children: [{
539 + displayName: 'RCText',
540 + children: [{
541 + displayName: '#text',
542 + text: 'Hi.',
543 + }],
544 + }],
545 + };
546 +
547 + var elementAfter = <Text>Bye.</Text>;
548 + var treeAfter = {
549 + displayName: 'Text',
550 + children: [{
551 + displayName: 'RCText',
552 + children: [{
553 + displayName: '#text',
554 + text: 'Bye.',
555 + }],
556 + }],
557 + };
558 +
559 + assertTreeMatches([
560 + [elementBefore, treeBefore],
561 + [elementAfter, treeAfter],
562 + ]);
563 + });
564 +
565 + it('updates from no children to a single text child', () => {
566 + var elementBefore = <Text />;
567 + var treeBefore = {
568 + displayName: 'Text',
569 + children: [{
570 + displayName: 'RCText',
571 + children: [],
572 + }],
573 + };
574 +
575 + var elementAfter = <Text>Hi.</Text>;
576 + var treeAfter = {
577 + displayName: 'Text',
578 + children: [{
579 + displayName: 'RCText',
580 + children: [{
581 + displayName: '#text',
582 + text: 'Hi.',
583 + }],
584 + }],
585 + };
586 +
587 + assertTreeMatches([
588 + [elementBefore, treeBefore],
589 + [elementAfter, treeAfter],
590 + ]);
591 + });
592 +
593 + it('updates from a single text child to no children', () => {
594 + var elementBefore = <Text>Hi.</Text>;
595 + var treeBefore = {
596 + displayName: 'Text',
597 + children: [{
598 + displayName: 'RCText',
599 + children: [{
600 + displayName: '#text',
601 + text: 'Hi.',
602 + }],
603 + }],
604 + };
605 +
606 + var elementAfter = <Text />;
607 + var treeAfter = {
608 + displayName: 'Text',
609 + children: [{
610 + displayName: 'RCText',
611 + children: [],
612 + }],
613 + };
614 +
615 + assertTreeMatches([
616 + [elementBefore, treeBefore],
617 + [elementAfter, treeAfter],
618 + ]);
619 + });
620 +
621 + it('updates from no children to multiple text children', () => {
622 + var elementBefore = <Text />;
623 + var treeBefore = {
624 + displayName: 'Text',
625 + children: [{
626 + displayName: 'RCText',
627 + children: [],
628 + }],
629 + };
630 +
631 + var elementAfter = <Text>{'Hi.'}{'Bye.'}</Text>;
632 + var treeAfter = {
633 + displayName: 'Text',
634 + children: [{
635 + displayName: 'RCText',
636 + children: [{
637 + displayName: '#text',
638 + text: 'Hi.',
639 + }, {
640 + displayName: '#text',
641 + text: 'Bye.',
642 + }],
643 + }],
644 + };
645 +
646 + assertTreeMatches([
647 + [elementBefore, treeBefore],
648 + [elementAfter, treeAfter],
649 + ]);
650 + });
651 +
652 + it('updates from multiple text children to no children', () => {
653 + var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
654 + var treeBefore = {
655 + displayName: 'Text',
656 + children: [{
657 + displayName: 'RCText',
658 + children: [{
659 + displayName: '#text',
660 + text: 'Hi.',
661 + }, {
662 + displayName: '#text',
663 + text: 'Bye.',
664 + }],
665 + }],
666 + };
667 +
668 + var elementAfter = <Text />;
669 + var treeAfter = {
670 + displayName: 'Text',
671 + children: [{
672 + displayName: 'RCText',
673 + children: [],
674 + }],
675 + };
676 + assertTreeMatches([
677 + [elementBefore, treeBefore],
678 + [elementAfter, treeAfter],
679 + ]);
680 + });
681 +
682 + it('updates from one text child to multiple text children', () => {
683 + var elementBefore = <Text>Hi.</Text>;
684 + var treeBefore = {
685 + displayName: 'Text',
686 + children: [{
687 + displayName: 'RCText',
688 + children: [{
689 + displayName: '#text',
690 + text: 'Hi.',
691 + }],
692 + }],
693 + };
694 +
695 + var elementAfter = <Text>{'Hi.'}{'Bye.'}</Text>;
696 + var treeAfter = {
697 + displayName: 'Text',
698 + children: [{
699 + displayName: 'RCText',
700 + children: [{
701 + displayName: '#text',
702 + text: 'Hi.',
703 + }, {
704 + displayName: '#text',
705 + text: 'Bye.',
706 + }],
707 + }],
708 + };
709 +
710 + assertTreeMatches([
711 + [elementBefore, treeBefore],
712 + [elementAfter, treeAfter],
713 + ]);
714 + });
715 +
716 + it('updates from multiple text children to one text child', () => {
717 + var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
718 + var treeBefore = {
719 + displayName: 'Text',
720 + children: [{
721 + displayName: 'RCText',
722 + children: [{
723 + displayName: '#text',
724 + text: 'Hi.',
725 + }, {
726 + displayName: '#text',
727 + text: 'Bye.',
728 + }],
729 + }],
730 + };
731 +
732 + var elementAfter = <Text>Hi.</Text>;
733 + var treeAfter = {
734 + displayName: 'Text',
735 + children: [{
736 + displayName: 'RCText',
737 + children: [{
738 + displayName: '#text',
739 + text: 'Hi.',
740 + }],
741 + }],
742 + };
743 + assertTreeMatches([
744 + [elementBefore, treeBefore],
745 + [elementAfter, treeAfter],
746 + ]);
747 + });
748 +
749 + it('updates text nodes when reordering', () => {
750 + var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
751 + var treeBefore = {
752 + displayName: 'Text',
753 + children: [{
754 + displayName: 'RCText',
755 + children: [{
756 + displayName: '#text',
757 + text: 'Hi.',
758 + }, {
759 + displayName: '#text',
760 + text: 'Bye.',
761 + }],
762 + }],
763 + };
764 +
765 + var elementAfter = <Text>{'Bye.'}{'Hi.'}</Text>;
766 + var treeAfter = {
767 + displayName: 'Text',
768 + children: [{
769 + displayName: 'RCText',
770 + children: [{
771 + displayName: '#text',
772 + text: 'Bye.',
773 + }, {
774 + displayName: '#text',
775 + text: 'Hi.',
776 + }],
777 + }],
778 + };
779 + assertTreeMatches([
780 + [elementBefore, treeBefore],
781 + [elementAfter, treeAfter],
782 + ]);
783 + });
784 +
785 + it('updates native nodes when reordering with keys', () => {
786 + var elementBefore = (
787 + <View>
788 + <Text key="a">Hi.</Text>
789 + <Text key="b">Bye.</Text>
790 + </View>
791 + );
792 + var treeBefore = {
793 + displayName: 'View',
794 + children: [{
795 + displayName: 'Text',
796 + children: [{
797 + displayName: 'RCText',
798 + children: [{
799 + displayName: '#text',
800 + text: 'Hi.',
801 + }],
802 + }],
803 + }, {
804 + displayName: 'Text',
805 + children: [{
806 + displayName: 'RCText',
807 + children: [{
808 + displayName: '#text',
809 + text: 'Bye.',
810 + }],
811 + }],
812 + }],
813 + };
814 +
815 + var elementAfter = (
816 + <View>
817 + <Text key="b">Bye.</Text>
818 + <Text key="a">Hi.</Text>
819 + </View>
820 + );
821 + var treeAfter = {
822 + displayName: 'View',
823 + children: [{
824 + displayName: 'Text',
825 + children: [{
826 + displayName: 'RCText',
827 + children: [{
828 + displayName: '#text',
829 + text: 'Bye.',
830 + }],
831 + }],
832 + }, {
833 + displayName: 'Text',
834 + children: [{
835 + displayName: 'RCText',
836 + children: [{
837 + displayName: '#text',
838 + text: 'Hi.',
839 + }],
840 + }],
841 + }],
842 + };
843 +
844 + assertTreeMatches([
845 + [elementBefore, treeBefore],
846 + [elementAfter, treeAfter],
847 + ]);
848 + });
849 +
850 + it('updates native nodes when reordering with keys', () => {
851 + var elementBefore = (
852 + <View>
853 + <Text>Hi.</Text>
854 + <Text>Bye.</Text>
855 + </View>
856 + );
857 + var treeBefore = {
858 + displayName: 'View',
859 + children: [{
860 + displayName: 'Text',
861 + children: [{
862 + displayName: 'RCText',
863 + children: [{
864 + displayName: '#text',
865 + text: 'Hi.',
866 + }],
867 + }],
868 + }, {
869 + displayName: 'Text',
870 + children: [{
871 + displayName: 'RCText',
872 + children: [{
873 + displayName: '#text',
874 + text: 'Bye.',
875 + }],
876 + }],
877 + }],
878 + };
879 +
880 + var elementAfter = (
881 + <View>
882 + <Text>Bye.</Text>
883 + <Text>Hi.</Text>
884 + </View>
885 + );
886 + var treeAfter = {
887 + displayName: 'View',
888 + children: [{
889 + displayName: 'Text',
890 + children: [{
891 + displayName: 'RCText',
892 + children: [{
893 + displayName: '#text',
894 + text: 'Bye.',
895 + }],
896 + }],
897 + }, {
898 + displayName: 'Text',
899 + children: [{
900 + displayName: 'RCText',
901 + children: [{
902 + displayName: '#text',
903 + text: 'Hi.',
904 + }],
905 + }],
906 + }],
907 + };
908 +
909 + assertTreeMatches([
910 + [elementBefore, treeBefore],
911 + [elementAfter, treeAfter],
912 + ]);
913 + });
914 +
915 + it('updates a single composite child of a different type', () => {
916 + function Foo() {
917 + return null;
918 + }
919 +
920 + function Bar() {
921 + return null;
922 + }
923 +
924 + var elementBefore = <View><Foo /></View>;
925 + var treeBefore = {
926 + displayName: 'View',
927 + children: [{
928 + displayName: 'Foo',
929 + children: [],
930 + }],
931 + };
932 +
933 + var elementAfter = <View><Bar /></View>;
934 + var treeAfter = {
935 + displayName: 'View',
936 + children: [{
937 + displayName: 'Bar',
938 + children: [],
939 + }],
940 + };
941 +
942 + assertTreeMatches([
943 + [elementBefore, treeBefore],
944 + [elementAfter, treeAfter],
945 + ]);
946 + });
947 +
948 + it('updates a single composite child of the same type', () => {
949 + function Foo({ children }) {
950 + return children;
951 + }
952 +
953 + var elementBefore = <View><Foo><View /></Foo></View>;
954 + var treeBefore = {
955 + displayName: 'View',
956 + children: [{
957 + displayName: 'Foo',
958 + children: [{
959 + displayName: 'View',
960 + children: [],
961 + }],
962 + }],
963 + };
964 +
965 + var elementAfter = <View><Foo><Image /></Foo></View>;
966 + var treeAfter = {
967 + displayName: 'View',
968 + children: [{
969 + displayName: 'Foo',
970 + children: [{
971 + displayName: 'Image',
972 + children: [],
973 + }],
974 + }],
975 + };
976 +
977 + assertTreeMatches([
978 + [elementBefore, treeBefore],
979 + [elementAfter, treeAfter],
980 + ]);
981 + });
982 +
983 + it('updates from no children to a single composite child', () => {
984 + function Foo() {
985 + return null;
986 + }
987 +
988 + var elementBefore = <View />;
989 + var treeBefore = {
990 + displayName: 'View',
991 + children: [],
992 + };
993 +
994 + var elementAfter = <View><Foo /></View>;
995 + var treeAfter = {
996 + displayName: 'View',
997 + children: [{
998 + displayName: 'Foo',
999 + children: [],
1000 + }],
1001 + };
1002 +
1003 + assertTreeMatches([
1004 + [elementBefore, treeBefore],
1005 + [elementAfter, treeAfter],
1006 + ]);
1007 + });
1008 +
1009 + it('updates from a single composite child to no children', () => {
1010 + function Foo() {
1011 + return null;
1012 + }
1013 +
1014 + var elementBefore = <View><Foo /></View>;
1015 + var treeBefore = {
1016 + displayName: 'View',
1017 + children: [{
1018 + displayName: 'Foo',
1019 + children: [],
1020 + }],
1021 + };
1022 +
1023 + var elementAfter = <View />;
1024 + var treeAfter = {
1025 + displayName: 'View',
1026 + children: [],
1027 + };
1028 +
1029 + assertTreeMatches([
1030 + [elementBefore, treeBefore],
1031 + [elementAfter, treeAfter],
1032 + ]);
1033 + });
1034 +
1035 + it('updates mixed children', () => {
1036 + function Foo() {
1037 + return <View />;
1038 + }
1039 + var element1 = (
1040 + <View>
1041 + <Text>hi</Text>
1042 + {false}
1043 + <Text>{42}</Text>
1044 + {null}
1045 + <Foo />
1046 + </View>
1047 + );
1048 + var tree1 = {
1049 + displayName: 'View',
1050 + children: [{
1051 + displayName: 'Text',
1052 + children: [{
1053 + displayName: 'RCText',
1054 + children: [{
1055 + displayName: '#text',
1056 + text: 'hi',
1057 + }],
1058 + }],
1059 + }, {
1060 + displayName: 'Text',
1061 + children: [{
1062 + displayName: 'RCText',
1063 + children: [{
1064 + displayName: '#text',
1065 + text: '42',
1066 + }],
1067 + }],
1068 + }, {
1069 + displayName: 'Foo',
1070 + children: [{
1071 + displayName: 'View',
1072 + children: [],
1073 + }],
1074 + }],
1075 + };
1076 +
1077 + var element2 = (
1078 + <View>
1079 + <Foo />
1080 + {false}
1081 + <Text>hi</Text>
1082 + {null}
1083 + </View>
1084 + );
1085 + var tree2 = {
1086 + displayName: 'View',
1087 + children: [{
1088 + displayName: 'Foo',
1089 + children: [{
1090 + displayName: 'View',
1091 + children: [],
1092 + }],
1093 + }, {
1094 + displayName: 'Text',
1095 + children: [{
1096 + displayName: 'RCText',
1097 + children: [{
1098 + displayName: '#text',
1099 + text: 'hi',
1100 + }],
1101 + }],
1102 + }],
1103 + };
1104 +
1105 + var element3 = (
1106 + <View>
1107 + <Foo />
1108 + </View>
1109 + );
1110 + var tree3 = {
1111 + displayName: 'View',
1112 + children: [{
1113 + displayName: 'Foo',
1114 + children: [{
1115 + displayName: 'View',
1116 + children: [],
1117 + }],
1118 + }],
1119 + };
1120 +
1121 + assertTreeMatches([
1122 + [element1, tree1],
1123 + [element2, tree2],
1124 + [element3, tree3],
1125 + ]);
1126 + });
1127 + });
1128 +
1129 + describe('functional component', () => {
1130 + it('updates with a native child', () => {
1131 + function Foo({ children }) {
1132 + return children;
1133 + }
1134 +
1135 + var elementBefore = <Foo><View /></Foo>;
1136 + var treeBefore = {
1137 + displayName: 'Foo',
1138 + children: [{
1139 + displayName: 'View',
1140 + children: [],
1141 + }],
1142 + };
1143 +
1144 + var elementAfter = <Foo><Image /></Foo>;
1145 + var treeAfter = {
1146 + displayName: 'Foo',
1147 + children: [{
1148 + displayName: 'Image',
1149 + children: [],
1150 + }],
1151 + };
1152 +
1153 + assertTreeMatches([
1154 + [elementBefore, treeBefore],
1155 + [elementAfter, treeAfter],
1156 + ]);
1157 + });
1158 +
1159 + it('updates from null to a native child', () => {
1160 + function Foo({ children }) {
1161 + return children;
1162 + }
1163 +
1164 + var elementBefore = <Foo>{null}</Foo>;
1165 + var treeBefore = {
1166 + displayName: 'Foo',
1167 + children: [],
1168 + };
1169 +
1170 + var elementAfter = <Foo><View /></Foo>;
1171 + var treeAfter = {
1172 + displayName: 'Foo',
1173 + children: [{
1174 + displayName: 'View',
1175 + children: [],
1176 + }],
1177 + };
1178 +
1179 + assertTreeMatches([
1180 + [elementBefore, treeBefore],
1181 + [elementAfter, treeAfter],
1182 + ]);
1183 + });
1184 +
1185 + it('updates from a native child to null', () => {
1186 + function Foo({ children }) {
1187 + return children;
1188 + }
1189 +
1190 + var elementBefore = <Foo><View /></Foo>;
1191 + var treeBefore = {
1192 + displayName: 'Foo',
1193 + children: [{
1194 + displayName: 'View',
1195 + children: [],
1196 + }],
1197 + };
1198 +
1199 + var elementAfter = <Foo>{null}</Foo>;
1200 + var treeAfter = {
1201 + displayName: 'Foo',
1202 + children: [],
1203 + };
1204 +
1205 + assertTreeMatches([
1206 + [elementBefore, treeBefore],
1207 + [elementAfter, treeAfter],
1208 + ]);
1209 + });
1210 +
1211 + it('updates from a native child to a composite child', () => {
1212 + function Bar() {
1213 + return null;
1214 + }
1215 +
1216 + function Foo({ children }) {
1217 + return children;
1218 + }
1219 +
1220 + var elementBefore = <Foo><View /></Foo>;
1221 + var treeBefore = {
1222 + displayName: 'Foo',
1223 + children: [{
1224 + displayName: 'View',
1225 + children: [],
1226 + }],
1227 + };
1228 +
1229 + var elementAfter = <Foo><Bar /></Foo>;
1230 + var treeAfter = {
1231 + displayName: 'Foo',
1232 + children: [{
1233 + displayName: 'Bar',
1234 + children: [],
1235 + }],
1236 + };
1237 +
1238 + assertTreeMatches([
1239 + [elementBefore, treeBefore],
1240 + [elementAfter, treeAfter],
1241 + ]);
1242 + });
1243 +
1244 + it('updates from a composite child to a native child', () => {
1245 + function Bar() {
1246 + return null;
1247 + }
1248 +
1249 + function Foo({ children }) {
1250 + return children;
1251 + }
1252 +
1253 + var elementBefore = <Foo><Bar /></Foo>;
1254 + var treeBefore = {
1255 + displayName: 'Foo',
1256 + children: [{
1257 + displayName: 'Bar',
1258 + children: [],
1259 + }],
1260 + };
1261 +
1262 + var elementAfter = <Foo><View /></Foo>;
1263 + var treeAfter = {
1264 + displayName: 'Foo',
1265 + children: [{
1266 + displayName: 'View',
1267 + children: [],
1268 + }],
1269 + };
1270 +
1271 + assertTreeMatches([
1272 + [elementBefore, treeBefore],
1273 + [elementAfter, treeAfter],
1274 + ]);
1275 + });
1276 +
1277 + it('updates from null to a composite child', () => {
1278 + function Bar() {
1279 + return null;
1280 + }
1281 +
1282 + function Foo({ children }) {
1283 + return children;
1284 + }
1285 +
1286 + var elementBefore = <Foo>{null}</Foo>;
1287 + var treeBefore = {
1288 + displayName: 'Foo',
1289 + children: [],
1290 + };
1291 +
1292 + var elementAfter = <Foo><Bar /></Foo>;
1293 + var treeAfter = {
1294 + displayName: 'Foo',
1295 + children: [{
1296 + displayName: 'Bar',
1297 + children: [],
1298 + }],
1299 + };
1300 +
1301 + assertTreeMatches([
1302 + [elementBefore, treeBefore],
1303 + [elementAfter, treeAfter],
1304 + ]);
1305 + });
1306 +
1307 + it('updates from a composite child to null', () => {
1308 + function Bar() {
1309 + return null;
1310 + }
1311 +
1312 + function Foo({ children }) {
1313 + return children;
1314 + }
1315 +
1316 + var elementBefore = <Foo><Bar /></Foo>;
1317 + var treeBefore = {
1318 + displayName: 'Foo',
1319 + children: [{
1320 + displayName: 'Bar',
1321 + children: [],
1322 + }],
1323 + };
1324 +
1325 + var elementAfter = <Foo>{null}</Foo>;
1326 + var treeAfter = {
1327 + displayName: 'Foo',
1328 + children: [],
1329 + };
1330 +
1331 + assertTreeMatches([
1332 + [elementBefore, treeBefore],
1333 + [elementAfter, treeAfter],
1334 + ]);
1335 + });
1336 + });
1337 +
1338 + describe('class component', () => {
1339 + it('updates with a native child', () => {
1340 + var Foo = React.createClass({
1341 + render() {
1342 + return this.props.children;
1343 + },
1344 + });
1345 +
1346 + var elementBefore = <Foo><View /></Foo>;
1347 + var treeBefore = {
1348 + displayName: 'Foo',
1349 + children: [{
1350 + displayName: 'View',
1351 + children: [],
1352 + }],
1353 + };
1354 +
1355 + var elementAfter = <Foo><Image /></Foo>;
1356 + var treeAfter = {
1357 + displayName: 'Foo',
1358 + children: [{
1359 + displayName: 'Image',
1360 + children: [],
1361 + }],
1362 + };
1363 +
1364 + assertTreeMatches([
1365 + [elementBefore, treeBefore],
1366 + [elementAfter, treeAfter],
1367 + ]);
1368 + });
1369 +
1370 + it('updates from null to a native child', () => {
1371 + var Foo = React.createClass({
1372 + render() {
1373 + return this.props.children;
1374 + },
1375 + });
1376 +
1377 + var elementBefore = <Foo>{null}</Foo>;
1378 + var treeBefore = {
1379 + displayName: 'Foo',
1380 + children: [],
1381 + };
1382 +
1383 + var elementAfter = <Foo><View /></Foo>;
1384 + var treeAfter = {
1385 + displayName: 'Foo',
1386 + children: [{
1387 + displayName: 'View',
1388 + children: [],
1389 + }],
1390 + };
1391 +
1392 + assertTreeMatches([
1393 + [elementBefore, treeBefore],
1394 + [elementAfter, treeAfter],
1395 + ]);
1396 + });
1397 +
1398 + it('updates from a native child to null', () => {
1399 + var Foo = React.createClass({
1400 + render() {
1401 + return this.props.children;
1402 + },
1403 + });
1404 +
1405 + var elementBefore = <Foo><View /></Foo>;
1406 + var treeBefore = {
1407 + displayName: 'Foo',
1408 + children: [{
1409 + displayName: 'View',
1410 + children: [],
1411 + }],
1412 + };
1413 +
1414 + var elementAfter = <Foo>{null}</Foo>;
1415 + var treeAfter = {
1416 + displayName: 'Foo',
1417 + children: [],
1418 + };
1419 +
1420 + assertTreeMatches([
1421 + [elementBefore, treeBefore],
1422 + [elementAfter, treeAfter],
1423 + ]);
1424 + });
1425 +
1426 + it('updates from a native child to a composite child', () => {
1427 + var Bar = React.createClass({
1428 + render() {
1429 + return null;
1430 + },
1431 + });
1432 +
1433 + var Foo = React.createClass({
1434 + render() {
1435 + return this.props.children;
1436 + },
1437 + });
1438 +
1439 + var elementBefore = <Foo><View /></Foo>;
1440 + var treeBefore = {
1441 + displayName: 'Foo',
1442 + children: [{
1443 + displayName: 'View',
1444 + children: [],
1445 + }],
1446 + };
1447 +
1448 + var elementAfter = <Foo><Bar /></Foo>;
1449 + var treeAfter = {
1450 + displayName: 'Foo',
1451 + children: [{
1452 + displayName: 'Bar',
1453 + children: [],
1454 + }],
1455 + };
1456 +
1457 + assertTreeMatches([
1458 + [elementBefore, treeBefore],
1459 + [elementAfter, treeAfter],
1460 + ]);
1461 + });
1462 +
1463 + it('updates from a composite child to a native child', () => {
1464 + var Bar = React.createClass({
1465 + render() {
1466 + return null;
1467 + },
1468 + });
1469 +
1470 + var Foo = React.createClass({
1471 + render() {
1472 + return this.props.children;
1473 + },
1474 + });
1475 +
1476 + var elementBefore = <Foo><Bar /></Foo>;
1477 + var treeBefore = {
1478 + displayName: 'Foo',
1479 + children: [{
1480 + displayName: 'Bar',
1481 + children: [],
1482 + }],
1483 + };
1484 +
1485 + var elementAfter = <Foo><View /></Foo>;
1486 + var treeAfter = {
1487 + displayName: 'Foo',
1488 + children: [{
1489 + displayName: 'View',
1490 + children: [],
1491 + }],
1492 + };
1493 +
1494 + assertTreeMatches([
1495 + [elementBefore, treeBefore],
1496 + [elementAfter, treeAfter],
1497 + ]);
1498 + });
1499 +
1500 + it('updates from null to a composite child', () => {
1501 + var Bar = React.createClass({
1502 + render() {
1503 + return null;
1504 + },
1505 + });
1506 +
1507 + var Foo = React.createClass({
1508 + render() {
1509 + return this.props.children;
1510 + },
1511 + });
1512 +
1513 + var elementBefore = <Foo>{null}</Foo>;
1514 + var treeBefore = {
1515 + displayName: 'Foo',
1516 + children: [],
1517 + };
1518 +
1519 + var elementAfter = <Foo><Bar /></Foo>;
1520 + var treeAfter = {
1521 + displayName: 'Foo',
1522 + children: [{
1523 + displayName: 'Bar',
1524 + children: [],
1525 + }],
1526 + };
1527 +
1528 + assertTreeMatches([
1529 + [elementBefore, treeBefore],
1530 + [elementAfter, treeAfter],
1531 + ]);
1532 + });
1533 +
1534 + it('updates from a composite child to null', () => {
1535 + var Bar = React.createClass({
1536 + render() {
1537 + return null;
1538 + },
1539 + });
1540 +
1541 + var Foo = React.createClass({
1542 + render() {
1543 + return this.props.children;
1544 + },
1545 + });
1546 +
1547 + var elementBefore = <Foo><Bar /></Foo>;
1548 + var treeBefore = {
1549 + displayName: 'Foo',
1550 + children: [{
1551 + displayName: 'Bar',
1552 + children: [],
1553 + }],
1554 + };
1555 +
1556 + var elementAfter = <Foo>{null}</Foo>;
1557 + var treeAfter = {
1558 + displayName: 'Foo',
1559 + children: [],
1560 + };
1561 +
1562 + assertTreeMatches([
1563 + [elementBefore, treeBefore],
1564 + [elementAfter, treeAfter],
1565 + ]);
1566 + });
1567 + });
1568 + });
1569 +
1570 + it('tracks owner correctly', () => {
1571 + class Foo extends React.Component {
1572 + render() {
1573 + return <Bar><Text>Hi.</Text></Bar>;
1574 + }
1575 + }
1576 + function Bar({children}) {
1577 + return <View>{children}<Text>Mom</Text></View>;
1578 + }
1579 +
1580 + // Note that owner is not calculated for text nodes
1581 + // because they are not created from real elements.
1582 + var element = <View><Foo /></View>;
1583 + var tree = {
1584 + displayName: 'View',
1585 + children: [{
1586 + displayName: 'Foo',
1587 + children: [{
1588 + displayName: 'Bar',
1589 + ownerDisplayName: 'Foo',
1590 + children: [{
1591 + displayName: 'View',
1592 + ownerDisplayName: 'Bar',
1593 + children: [{
1594 + displayName: 'Text',
1595 + ownerDisplayName: 'Foo',
1596 + children: [{
1597 + displayName: 'RCText',
1598 + ownerDisplayName: 'Text',
1599 + children: [{
1600 + displayName: '#text',
1601 + text: 'Hi.',
1602 + }],
1603 + }],
1604 + }, {
1605 + displayName: 'Text',
1606 + ownerDisplayName: 'Bar',
1607 + children: [{
1608 + displayName: 'RCText',
1609 + ownerDisplayName: 'Text',
1610 + children: [{
1611 + displayName: '#text',
1612 + text: 'Mom',
1613 + }],
1614 + }],
1615 + }],
1616 + }],
1617 + }],
1618 + }],
1619 + };
1620 + assertTreeMatches([element, tree], {includeOwnerDisplayName: true});
1621 + });
1622 +
1623 + it('preserves unmounted components until purge', () => {
1624 + var renderBar = true;
1625 + var fooInstance;
1626 + var barInstance;
1627 +
1628 + class Foo extends React.Component {
1629 + render() {
1630 + fooInstance = ReactInstanceMap.get(this);
1631 + return renderBar ? <Bar /> : null;
1632 + }
1633 + }
1634 +
1635 + class Bar extends React.Component {
1636 + render() {
1637 + barInstance = ReactInstanceMap.get(this);
1638 + return null;
1639 + }
1640 + }
1641 +
1642 + ReactNative.render(<Foo />, 1);
1643 + expect(
1644 + getTree(barInstance._debugID, {
1645 + includeParentDisplayName: true,
1646 + expectedParentID: fooInstance._debugID,
1647 + })
1648 + ).toEqual({
1649 + displayName: 'Bar',
1650 + parentDisplayName: 'Foo',
1651 + children: [],
1652 + });
1653 +
1654 + renderBar = false;
1655 + ReactNative.render(<Foo />, 1);
1656 + expect(
1657 + getTree(barInstance._debugID, {
1658 + includeParentDisplayName: true,
1659 + expectedParentID: fooInstance._debugID,
1660 + })
1661 + ).toEqual({
1662 + displayName: 'Bar',
1663 + parentDisplayName: 'Foo',
1664 + children: [],
1665 + });
1666 +
1667 + ReactNative.unmountComponentAtNode(1);
1668 + expect(
1669 + getTree(barInstance._debugID, {
1670 + includeParentDisplayName: true,
1671 + expectedParentID: fooInstance._debugID,
1672 + })
1673 + ).toEqual({
1674 + displayName: 'Bar',
1675 + parentDisplayName: 'Foo',
1676 + children: [],
1677 + });
1678 +
1679 + ReactComponentTreeDevtool.purgeUnmountedComponents();
1680 + expect(
1681 + getTree(barInstance._debugID, {includeParentDisplayName: true})
1682 + ).toEqual({
1683 + displayName: 'Unknown',
1684 + children: [],
1685 + });
1686 + });
1687 +
1688 + it('does not report top-level wrapper as a root', () => {
1689 + ReactNative.render(<View><Image /></View>, 1);
1690 + expect(getRootDisplayNames()).toEqual(['View']);
1691 +
1692 + ReactNative.render(<View><Text /></View>, 1);
1693 + expect(getRootDisplayNames()).toEqual(['View']);
1694 +
1695 + ReactNative.unmountComponentAtNode(1);
1696 + expect(getRootDisplayNames()).toEqual([]);
1697 +
1698 + ReactComponentTreeDevtool.purgeUnmountedComponents();
1699 + expect(getRootDisplayNames()).toEqual([]);
1700 +
1701 + // This currently contains TopLevelWrapper until purge
1702 + // so we only check it at the very end.
1703 + expect(getRegisteredDisplayNames()).toEqual([]);
1704 + });
1705 +});
src/renderers/native/ReactNative/ReactNativeMount.js
+13
@@ -12,6 +12,7 @@
12 'use strict';
13
14 var ReactElement = require('ReactElement');
15 +var ReactInstrumentation = require('ReactInstrumentation');
16 var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
17 var ReactNativeTagHandles = require('ReactNativeTagHandles');
18 var ReactPerf = require('ReactPerf');
@@ -138,6 +139,12 @@ var ReactNativeMount = {
139 var instance = instantiateReactComponent(nextWrappedElement);
140 ReactNativeMount._instancesByContainerID[containerTag] = instance;
141
142 + if (__DEV__) {
143 + // Mute future events from the top level wrapper.
144 + // It is an implementation detail that devtools should not know about.
145 + instance._debugID = 0;
146 + }
147 +
148 // The initial render is synchronous but any updates that happen during
149 // rendering, in componentWillMount or componentDidMount, will be batched
150 // according to the current batching strategy.
@@ -147,6 +154,12 @@ var ReactNativeMount = {
154 instance,
155 containerTag
156 );
157 + if (__DEV__) {
158 + // The instance here is TopLevelWrapper so we report mount for its child.
159 + ReactInstrumentation.debugTool.onMountRootComponent(
160 + instance._renderedComponent._debugID
161 + );
162 + }
163 var component = instance.getPublicInstance();
164 if (callback) {
165 callback.call(component);
src/renderers/native/ReactNative/ReactNativeTextComponent.js
+11
@@ -11,6 +11,7 @@
11
12 'use strict';
13
14 +var ReactInstrumentation = require('ReactInstrumentation');
15 var ReactNativeComponentTree = require('ReactNativeComponentTree');
16 var ReactNativeTagHandles = require('ReactNativeTagHandles');
17 var UIManager = require('UIManager');
@@ -28,6 +29,10 @@ var ReactNativeTextComponent = function(text) {
29 Object.assign(ReactNativeTextComponent.prototype, {
30
31 mountComponent: function(transaction, nativeParent, nativeContainerInfo, context) {
32 + if (__DEV__) {
33 + ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText);
34 + }
35 +
36 // TODO: nativeParent should have this context already. Stop abusing context.
37 invariant(
38 context.isInAParentText,
@@ -65,6 +70,12 @@ Object.assign(ReactNativeTextComponent.prototype, {
70 'RCTRawText',
71 {text: this._stringText}
72 );
73 + if (__DEV__) {
74 + ReactInstrumentation.debugTool.onSetText(
75 + this._debugID,
76 + nextStringText
77 + );
78 + }
79 }
80 }
81 },
src/renderers/native/ReactNative/__mocks__/UIManager.js
+2
@@ -16,6 +16,8 @@ var RCTUIManager = {
16 setChildren: jest.fn(),
17 manageChildren: jest.fn(),
18 updateView: jest.fn(),
19 + removeSubviewsFromContainerWithID: jest.fn(),
20 + replaceExistingNonRootView: jest.fn(),
21 };
22
23 module.exports = RCTUIManager;
src/renderers/native/ReactNative/__mocks__/View.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Copyright 2013-2015, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + */
9 +
10 +'use strict';
11 +
12 +var createReactNativeComponentClass = require('createReactNativeComponentClass');
13 +
14 +var View = createReactNativeComponentClass({
15 + validAttributes: {},
16 + uiViewClassName: 'View',
17 +});
18 +
19 +module.exports = View;