Implement the same search strategy in ReactTestUtils as findDOMNode
This was supposed to fix an issue in refs-test but instead it revealed that this strategy is broken. The problem is that Placement effect is not sufficient when the insertion is completed since the effect flag is reset then and the previous tree has no effects in it to indicate that this is the wrong tree.
Sebastian Markbage committed
Nov 21, 2016 at 04:48 UTC
7dd8fc549e39ce960a1acb7c7cb00b4ed8d7c17e
3 files changed
+25
-9
scripts/fiber/tests-failing.txt
+1
@@ -145,4 +145,5 @@ src/renderers/shared/stack/reconciler/__tests__/refs-test.js
145
* Should increase refs with an increase in divs
146
147
src/test/__tests__/ReactTestUtils-test.js
148
+* traverses children in the correct order
149
* should support injected wrapper components as DOM components
scripts/fiber/tests-passing.txt
-1
@@ -1539,7 +1539,6 @@ src/test/__tests__/ReactTestUtils-test.js
1539
* can scryRenderedDOMComponentsWithClass with TextComponent
1540
* can scryRenderedDOMComponentsWithClass with className contains \n
1541
* can scryRenderedDOMComponentsWithClass with multiple classes
1542
-* traverses children in the correct order
1542
* should change the value of an input field
1543
* should change the value of an input field in a component
1544
* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering
src/test/ReactTestUtils.js
+24
-8
@@ -22,6 +22,7 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree');
22
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
23
var ReactInstanceMap = require('ReactInstanceMap');
24
var ReactTypeOfWork = require('ReactTypeOfWork');
25
+var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
26
var ReactGenericBatching = require('ReactGenericBatching');
27
var SyntheticEvent = require('SyntheticEvent');
28
var ReactShallowRenderer = require('ReactShallowRenderer');
@@ -34,9 +35,12 @@ var {
35
ClassComponent,
36
FunctionalComponent,
37
HostComponent,
37
- HostContainer,
38
HostText,
39
} = ReactTypeOfWork;
40
+var {
41
+ NoEffect,
42
+ Placement,
43
+} = ReactTypeOfSideEffect;
44
45
function Event(suffix) {}
46
@@ -88,6 +92,12 @@ function findAllInRenderedFiberTreeInternal(fiber, test) {
92
) {
93
return [];
94
}
95
+ if ((fiber.effectTag & Placement) !== NoEffect || !fiber.return) {
96
+ // If any node along the way was deleted, or is an insertion, that means
97
+ // that we're actually in a work in progress to update this component with
98
+ // a different component. We need to look in the "current" fiber instead.
99
+ return null;
100
+ }
101
var publicInst = fiber.stateNode;
102
var ret = publicInst && test(publicInst) ? [publicInst] : [];
103
var child = fiber.child;
@@ -213,14 +223,20 @@ var ReactTestUtils = {
223
var internalInstance = ReactInstanceMap.get(inst);
224
if (internalInstance && typeof internalInstance.tag === 'number') {
225
var fiber = internalInstance;
216
- var root = fiber;
217
- while (root.return) {
218
- root = root.return;
226
+ if (!fiber.child && fiber.alternate) {
227
+ // When we don't have children, we try the alternate first to see if it
228
+ // has any current children first.
229
+ fiber = fiber.alternate;
230
+ }
231
+ var results = findAllInRenderedFiberTreeInternal(fiber, test);
232
+ if (results === null) {
233
+ // Null is a sentinel that indicates that this was the wrong fiber.
234
+ results = findAllInRenderedFiberTreeInternal(fiber.alternate, test);
235
+ if (results === null) {
236
+ throw new Error('This should never happen.');
237
+ }
238
}
220
- var isRootCurrent = root.tag === HostContainer && root.stateNode.current === root;
221
- // Make sure we're introspecting the current tree
222
- var current = isRootCurrent ? fiber : fiber.alternate;
223
- return findAllInRenderedFiberTreeInternal(current, test);
239
+ return results;
240
} else {
241
return findAllInRenderedStackTreeInternal(internalInstance, test);
242
}