@@ -540,6 +540,83 @@ describe('renderer: teleport', () => {
540540 expect ( serializeInner ( targetB ) ) . toBe ( `<div>teleported</div>` )
541541 } )
542542
543+ test ( 'should move targetStart and keep appended children in order after target change' , async ( ) => {
544+ const root = document . createElement ( 'div' )
545+ const targetA = document . createElement ( 'div' )
546+ const targetB = document . createElement ( 'div' )
547+ document . body . append ( root , targetA , targetB )
548+
549+ const target = ref < HTMLElement > ( targetA )
550+ const showB = ref ( false )
551+
552+ domRender (
553+ h ( ( ) =>
554+ h (
555+ Teleport ,
556+ { to : target . value } ,
557+ showB . value ? [ h ( 'div' , 'A' ) , h ( 'div' , 'B' ) ] : [ h ( 'div' , 'A' ) ] ,
558+ ) ,
559+ ) ,
560+ root ,
561+ )
562+ await nextTick ( )
563+
564+ expect ( targetA . innerHTML ) . toBe ( `<div>A</div>` )
565+
566+ target . value = targetB
567+ await nextTick ( )
568+
569+ // targetStart must not be left behind in the old target
570+ expect ( targetA . childNodes . length ) . toBe ( 0 )
571+ // targetStart, A, targetAnchor
572+ expect ( targetB . childNodes . length ) . toBe ( 3 )
573+
574+ showB . value = true
575+ await nextTick ( )
576+
577+ expect ( targetB . innerHTML ) . toBe ( `<div>A</div><div>B</div>` )
578+
579+ domRender ( null , root )
580+ root . remove ( )
581+ targetA . remove ( )
582+ targetB . remove ( )
583+ } )
584+
585+ test ( 'should not crash when root is replaced after target changed from own container' , async ( ) => {
586+ const root = document . createElement ( 'div' )
587+ const targetB = document . createElement ( 'div' )
588+ document . body . append ( root , targetB )
589+
590+ const target = ref < HTMLElement > ( root )
591+ const swapped = ref ( false )
592+
593+ const Comp = {
594+ render : ( ) =>
595+ swapped . value
596+ ? h ( 'div' , 'swapped' )
597+ : [
598+ h ( Teleport , { to : target . value } , [ h ( 'div' , 'A' ) ] ) ,
599+ h ( 'div' , 'x' ) ,
600+ ] ,
601+ }
602+
603+ domRender ( h ( Comp ) , root )
604+ await nextTick ( )
605+
606+ target . value = targetB
607+ await nextTick ( )
608+
609+ swapped . value = true
610+ await nextTick ( )
611+
612+ expect ( root . innerHTML ) . toBe ( `<div>swapped</div>` )
613+ expect ( targetB . childNodes . length ) . toBe ( 0 )
614+
615+ domRender ( null , root )
616+ root . remove ( )
617+ targetB . remove ( )
618+ } )
619+
543620 test ( 'move cached text nodes' , async ( ) => {
544621 document . body . innerHTML = ''
545622 const root = document . createElement ( 'div' )
0 commit comments