@samitouri / QOS-React / commits / 7dc1a176b5

Skip special nodes when reading TestInstance.parent (#12813)

Dan Abramov committed May 15, 2018 at 11:11 UTC 7dc1a176b5c50739b200a9d8612a42b110289d22
2 files changed +51 -30
packages/react-test-renderer/src/ReactTestRenderer.js
+14 -28
@@ -245,10 +245,14 @@ class ReactTestInstance {
245 }
246
247 get parent(): ?ReactTestInstance {
248 - const parent = this._fiber.return;
249 - return parent === null || parent.tag === HostRoot
250 - ? null
251 - : wrapFiber(parent);
248 + let parent = this._fiber.return;
249 + while (parent !== null) {
250 + if (validWrapperTypes.has(parent.tag)) {
251 + return wrapFiber(parent);
252 + }
253 + parent = parent.return;
254 + }
255 + return null;
256 }
257
258 get children(): Array<ReactTestInstance | string> {
@@ -262,30 +266,12 @@ class ReactTestInstance {
266 node = node.child;
267 outer: while (true) {
268 let descend = false;
265 - switch (node.tag) {
266 - case FunctionalComponent:
267 - case ClassComponent:
268 - case HostComponent:
269 - case ForwardRef:
270 - children.push(wrapFiber(node));
271 - break;
272 - case HostText:
273 - children.push('' + node.memoizedProps);
274 - break;
275 - case Fragment:
276 - case ContextProvider:
277 - case ContextConsumer:
278 - case Mode:
279 - case Profiler:
280 - descend = true;
281 - break;
282 - default:
283 - invariant(
284 - false,
285 - 'Unsupported component type %s in test renderer. ' +
286 - 'This is probably a bug in React.',
287 - node.tag,
288 - );
269 + if (validWrapperTypes.has(node.tag)) {
270 + children.push(wrapFiber(node));
271 + } else if (node.tag === HostText) {
272 + children.push('' + node.memoizedProps);
273 + } else {
274 + descend = true;
275 }
276 if (descend && node.child !== null) {
277 node.child.return = node;
packages/react-test-renderer/src/__tests__/ReactTestRendererTraversal-test.js
+37 -2
@@ -12,6 +12,7 @@
12
13 const React = require('react');
14 let ReactTestRenderer;
15 +let Context;
16
17 const RCTView = 'RCTView';
18 const View = props => <RCTView {...props} />;
@@ -20,6 +21,7 @@ describe('ReactTestRendererTraversal', () => {
21 beforeEach(() => {
22 jest.resetModules();
23 ReactTestRenderer = require('react-test-renderer');
24 + Context = React.createContext(null);
25 });
26
27 class Example extends React.Component {
@@ -40,6 +42,17 @@ describe('ReactTestRendererTraversal', () => {
42 <React.unstable_Profiler id="test" onRender={() => {}}>
43 <ExampleForwardRef qux="qux" />
44 </React.unstable_Profiler>
45 + <React.Fragment>
46 + <React.Fragment>
47 + <Context.Provider value={null}>
48 + <Context.Consumer>
49 + {() => <View nested={true} />}
50 + </Context.Consumer>
51 + </Context.Provider>
52 + </React.Fragment>
53 + <View nested={true} />
54 + <View nested={true} />
55 + </React.Fragment>
56 </View>
57 </View>
58 );
@@ -61,7 +74,7 @@ describe('ReactTestRendererTraversal', () => {
74
75 // assert .props, .type and .parent attributes
76 const foo = render.root.find(hasFooProp);
64 - expect(foo.props.children).toHaveLength(8);
77 + expect(foo.props.children).toHaveLength(9);
78 expect(foo.type).toBe(View);
79 expect(render.root.parent).toBe(null);
80 expect(foo.children[0].parent).toBe(foo);
@@ -76,6 +89,7 @@ describe('ReactTestRendererTraversal', () => {
89 const hasNullProp = node => node.props.hasOwnProperty('null');
90 const hasVoidProp = node => node.props.hasOwnProperty('void');
91 const hasItselfProp = node => node.props.hasOwnProperty('itself');
92 + const hasNestedProp = node => node.props.hasOwnProperty('nested');
93
94 expect(() => render.root.find(hasFooProp)).not.toThrow(); // 1 match
95 expect(() => render.root.find(hasBarProp)).toThrow(); // >1 matches
@@ -83,6 +97,7 @@ describe('ReactTestRendererTraversal', () => {
97 expect(() => render.root.find(hasBingProp)).not.toThrow(); // 1 match
98 expect(() => render.root.find(hasNullProp)).not.toThrow(); // 1 match
99 expect(() => render.root.find(hasVoidProp)).toThrow(); // 0 matches
100 + expect(() => render.root.find(hasNestedProp)).toThrow(); // >1 matches
101
102 // same assertion as .find(), but confirm length
103 expect(render.root.findAll(hasFooProp, {deep: false})).toHaveLength(1);
@@ -91,6 +106,7 @@ describe('ReactTestRendererTraversal', () => {
106 expect(render.root.findAll(hasBingProp, {deep: false})).toHaveLength(1);
107 expect(render.root.findAll(hasNullProp, {deep: false})).toHaveLength(1);
108 expect(render.root.findAll(hasVoidProp, {deep: false})).toHaveLength(0);
109 + expect(render.root.findAll(hasNestedProp, {deep: false})).toHaveLength(3);
110
111 // note: with {deep: true}, .findAll() will continue to
112 // search children, even after finding a match
@@ -100,6 +116,7 @@ describe('ReactTestRendererTraversal', () => {
116 expect(render.root.findAll(hasBingProp)).toHaveLength(1); // no spread
117 expect(render.root.findAll(hasNullProp)).toHaveLength(1); // no spread
118 expect(render.root.findAll(hasVoidProp)).toHaveLength(0);
119 + expect(render.root.findAll(hasNestedProp, {deep: false})).toHaveLength(3);
120
121 const bing = render.root.find(hasBingProp);
122 expect(bing.find(hasBarProp)).toBe(bing);
@@ -130,7 +147,7 @@ describe('ReactTestRendererTraversal', () => {
147
148 expect(render.root.findAllByType(ExampleFn)).toHaveLength(1);
149 expect(render.root.findAllByType(View, {deep: false})).toHaveLength(1);
133 - expect(render.root.findAllByType(View)).toHaveLength(8);
150 + expect(render.root.findAllByType(View)).toHaveLength(11);
151 expect(render.root.findAllByType(ExampleNull)).toHaveLength(2);
152 expect(render.root.findAllByType(ExampleForwardRef)).toHaveLength(1);
153
@@ -164,4 +181,22 @@ describe('ReactTestRendererTraversal', () => {
181 expect(render.root.findAllByProps({baz})).toHaveLength(4);
182 expect(render.root.findAllByProps({qux})).toHaveLength(3);
183 });
184 +
185 + it('skips special nodes', () => {
186 + const render = ReactTestRenderer.create(<Example />);
187 + expect(render.root.findAllByType(React.Fragment)).toHaveLength(0);
188 + expect(render.root.findAllByType(Context.Consumer)).toHaveLength(0);
189 + expect(render.root.findAllByType(Context.Provider)).toHaveLength(0);
190 +
191 + const expectedParent = render.root.findByProps({foo: 'foo'}, {deep: false})
192 + .children[0];
193 + const nestedViews = render.root.findAllByProps(
194 + {nested: true},
195 + {deep: false},
196 + );
197 + expect(nestedViews.length).toBe(3);
198 + expect(nestedViews[0].parent).toBe(expectedParent);
199 + expect(nestedViews[1].parent).toBe(expectedParent);
200 + expect(nestedViews[2].parent).toBe(expectedParent);
201 + });
202 });