@@ -200,8 +200,45 @@ const validWrapperTypes = new Set([
200200 ClassComponent ,
201201 HostComponent ,
202202 ForwardRef ,
203+ // Normally skipped, but used when there's more than one root child.
204+ HostRoot ,
203205] ) ;
204206
207+ function getChildren ( parent : Fiber ) {
208+ const children = [ ] ;
209+ const startingNode = parent ;
210+ let node : Fiber = startingNode ;
211+ if ( node . child === null ) {
212+ return children ;
213+ }
214+ node . child . return = node ;
215+ node = node . child ;
216+ outer: while ( true ) {
217+ let descend = false ;
218+ if ( validWrapperTypes . has ( node . tag ) ) {
219+ children . push ( wrapFiber ( node ) ) ;
220+ } else if ( node . tag === HostText ) {
221+ children . push ( '' + node . memoizedProps ) ;
222+ } else {
223+ descend = true ;
224+ }
225+ if ( descend && node . child !== null ) {
226+ node . child . return = node ;
227+ node = node . child ;
228+ continue ;
229+ }
230+ while ( node . sibling === null ) {
231+ if ( node . return === startingNode ) {
232+ break outer;
233+ }
234+ node = ( node . return : any ) ;
235+ }
236+ ( node . sibling : any ) . return = node . return ;
237+ node = ( node . sibling : any ) ;
238+ }
239+ return children ;
240+ }
241+
205242class ReactTestInstance {
206243 _fiber : Fiber ;
207244
@@ -246,6 +283,13 @@ class ReactTestInstance {
246283 let parent = this . _fiber . return ;
247284 while ( parent !== null ) {
248285 if ( validWrapperTypes . has ( parent . tag ) ) {
286+ if ( parent . tag === HostRoot ) {
287+ // Special case: we only "materialize" instances for roots
288+ // if they have more than a single child. So we'll check that now.
289+ if ( getChildren ( parent ) . length < 2 ) {
290+ return null ;
291+ }
292+ }
249293 return wrapFiber ( parent ) ;
250294 }
251295 parent = parent . return ;
@@ -254,38 +298,7 @@ class ReactTestInstance {
254298 }
255299
256300 get children ( ) : Array < ReactTestInstance | string > {
257- const children = [ ] ;
258- const startingNode = this . _currentFiber ( ) ;
259- let node : Fiber = startingNode ;
260- if ( node . child === null ) {
261- return children ;
262- }
263- node . child . return = node ;
264- node = node . child ;
265- outer: while ( true ) {
266- let descend = false ;
267- if ( validWrapperTypes . has ( node . tag ) ) {
268- children . push ( wrapFiber ( node ) ) ;
269- } else if ( node . tag === HostText ) {
270- children . push ( '' + node . memoizedProps ) ;
271- } else {
272- descend = true ;
273- }
274- if ( descend && node . child !== null ) {
275- node . child . return = node ;
276- node = node . child ;
277- continue ;
278- }
279- while ( node . sibling === null ) {
280- if ( node . return === startingNode ) {
281- break outer;
282- }
283- node = ( node . return : any ) ;
284- }
285- ( node . sibling : any ) . return = node . return ;
286- node = ( node . sibling : any ) ;
287- }
288- return children ;
301+ return getChildren ( this . _currentFiber ( ) ) ;
289302 }
290303
291304 // Custom search functions
@@ -469,10 +482,20 @@ const ReactTestRendererFiber = {
469482 configurable : true ,
470483 enumerable : true ,
471484 get : function ( ) {
472- if ( root === null || root . current . child === null ) {
485+ if ( root === null ) {
486+ throw new Error ( "Can't access .root on unmounted test renderer" ) ;
487+ }
488+ const children = getChildren ( root . current ) ;
489+ if ( children . length === 0 ) {
473490 throw new Error ( "Can't access .root on unmounted test renderer" ) ;
491+ } else if ( children . length === 1 ) {
492+ // Normally, we skip the root and just give you the child.
493+ return children [ 0 ] ;
494+ } else {
495+ // However, we give you the root if there's more than one root child.
496+ // We could make this the behavior for all cases but it would be a breaking change.
497+ return wrapFiber ( root . current ) ;
474498 }
475- return wrapFiber ( root . current . child ) ;
476499 } ,
477500 } : Object ) ,
478501 ) ;
0 commit comments