@@ -265,7 +265,7 @@ describe('SSR hydration', () => {
265
265
const fn = vi . fn ( )
266
266
const teleportContainer = document . createElement ( 'div' )
267
267
teleportContainer . id = 'teleport'
268
- teleportContainer . innerHTML = `<span>foo</span><span class="foo"></span><!--teleport anchor-->`
268
+ teleportContainer . innerHTML = `<!--teleport start anchor-->< span>foo</span><span class="foo"></span><!--teleport anchor-->`
269
269
document . body . appendChild ( teleportContainer )
270
270
271
271
const { vnode, container } = mountWithHydration (
@@ -281,13 +281,14 @@ describe('SSR hydration', () => {
281
281
expect ( vnode . anchor ) . toBe ( container . lastChild )
282
282
283
283
expect ( vnode . target ) . toBe ( teleportContainer )
284
+ expect ( vnode . targetStart ) . toBe ( teleportContainer . childNodes [ 0 ] )
284
285
expect ( ( vnode . children as VNode [ ] ) [ 0 ] . el ) . toBe (
285
- teleportContainer . childNodes [ 0 ] ,
286
+ teleportContainer . childNodes [ 1 ] ,
286
287
)
287
288
expect ( ( vnode . children as VNode [ ] ) [ 1 ] . el ) . toBe (
288
- teleportContainer . childNodes [ 1 ] ,
289
+ teleportContainer . childNodes [ 2 ] ,
289
290
)
290
- expect ( vnode . targetAnchor ) . toBe ( teleportContainer . childNodes [ 2 ] )
291
+ expect ( vnode . targetAnchor ) . toBe ( teleportContainer . childNodes [ 3 ] )
291
292
292
293
// event handler
293
294
triggerEvent ( 'click' , teleportContainer . querySelector ( '.foo' ) ! )
@@ -296,7 +297,7 @@ describe('SSR hydration', () => {
296
297
msg . value = 'bar'
297
298
await nextTick ( )
298
299
expect ( teleportContainer . innerHTML ) . toBe (
299
- `<span>bar</span><span class="bar"></span><!--teleport anchor-->` ,
300
+ `<!--teleport start anchor-->< span>bar</span><span class="bar"></span><!--teleport anchor-->` ,
300
301
)
301
302
} )
302
303
@@ -326,7 +327,7 @@ describe('SSR hydration', () => {
326
327
327
328
const teleportHtml = ctx . teleports ! [ '#teleport2' ]
328
329
expect ( teleportHtml ) . toMatchInlineSnapshot (
329
- `"<span>foo</span><span class="foo"></span><!--teleport anchor--><span>foo2</span><span class="foo2"></span><!--teleport anchor-->"` ,
330
+ `"<!--teleport start anchor-->< span>foo</span><span class="foo"></span><!--teleport anchor--><!--teleport start anchor--><span>foo2</span><span class="foo2"></span><!--teleport anchor-->"` ,
330
331
)
331
332
332
333
teleportContainer . innerHTML = teleportHtml
@@ -342,16 +343,18 @@ describe('SSR hydration', () => {
342
343
expect ( teleportVnode2 . anchor ) . toBe ( container . childNodes [ 4 ] )
343
344
344
345
expect ( teleportVnode1 . target ) . toBe ( teleportContainer )
346
+ expect ( teleportVnode1 . targetStart ) . toBe ( teleportContainer . childNodes [ 0 ] )
345
347
expect ( ( teleportVnode1 as any ) . children [ 0 ] . el ) . toBe (
346
- teleportContainer . childNodes [ 0 ] ,
348
+ teleportContainer . childNodes [ 1 ] ,
347
349
)
348
- expect ( teleportVnode1 . targetAnchor ) . toBe ( teleportContainer . childNodes [ 2 ] )
350
+ expect ( teleportVnode1 . targetAnchor ) . toBe ( teleportContainer . childNodes [ 3 ] )
349
351
350
352
expect ( teleportVnode2 . target ) . toBe ( teleportContainer )
353
+ expect ( teleportVnode2 . targetStart ) . toBe ( teleportContainer . childNodes [ 4 ] )
351
354
expect ( ( teleportVnode2 as any ) . children [ 0 ] . el ) . toBe (
352
- teleportContainer . childNodes [ 3 ] ,
355
+ teleportContainer . childNodes [ 5 ] ,
353
356
)
354
- expect ( teleportVnode2 . targetAnchor ) . toBe ( teleportContainer . childNodes [ 5 ] )
357
+ expect ( teleportVnode2 . targetAnchor ) . toBe ( teleportContainer . childNodes [ 7 ] )
355
358
356
359
// // event handler
357
360
triggerEvent ( 'click' , teleportContainer . querySelector ( '.foo' ) ! )
@@ -363,7 +366,7 @@ describe('SSR hydration', () => {
363
366
msg . value = 'bar'
364
367
await nextTick ( )
365
368
expect ( teleportContainer . innerHTML ) . toMatchInlineSnapshot (
366
- `"<span>bar</span><span class="bar"></span><!--teleport anchor--><span>bar2</span><span class="bar2"></span><!--teleport anchor-->"` ,
369
+ `"<!--teleport start anchor-->< span>bar</span><span class="bar"></span><!--teleport anchor--><!--teleport start anchor--><span>bar2</span><span class="bar2"></span><!--teleport anchor-->"` ,
367
370
)
368
371
} )
369
372
@@ -390,7 +393,9 @@ describe('SSR hydration', () => {
390
393
)
391
394
392
395
const teleportHtml = ctx . teleports ! [ '#teleport3' ]
393
- expect ( teleportHtml ) . toMatchInlineSnapshot ( `"<!--teleport anchor-->"` )
396
+ expect ( teleportHtml ) . toMatchInlineSnapshot (
397
+ `"<!--teleport start anchor--><!--teleport anchor-->"` ,
398
+ )
394
399
395
400
teleportContainer . innerHTML = teleportHtml
396
401
document . body . appendChild ( teleportContainer )
@@ -413,7 +418,8 @@ describe('SSR hydration', () => {
413
418
expect ( children [ 2 ] . el ) . toBe ( container . childNodes [ 6 ] )
414
419
415
420
expect ( teleportVnode . target ) . toBe ( teleportContainer )
416
- expect ( teleportVnode . targetAnchor ) . toBe ( teleportContainer . childNodes [ 0 ] )
421
+ expect ( teleportVnode . targetStart ) . toBe ( teleportContainer . childNodes [ 0 ] )
422
+ expect ( teleportVnode . targetAnchor ) . toBe ( teleportContainer . childNodes [ 1 ] )
417
423
418
424
// // event handler
419
425
triggerEvent ( 'click' , container . querySelector ( '.foo' ) ! )
@@ -454,7 +460,7 @@ describe('SSR hydration', () => {
454
460
test ( 'Teleport (as component root)' , ( ) => {
455
461
const teleportContainer = document . createElement ( 'div' )
456
462
teleportContainer . id = 'teleport4'
457
- teleportContainer . innerHTML = `hello<!--teleport anchor-->`
463
+ teleportContainer . innerHTML = `<!--teleport start anchor--> hello<!--teleport anchor-->`
458
464
document . body . appendChild ( teleportContainer )
459
465
460
466
const wrapper = {
@@ -483,7 +489,7 @@ describe('SSR hydration', () => {
483
489
test ( 'Teleport (nested)' , ( ) => {
484
490
const teleportContainer = document . createElement ( 'div' )
485
491
teleportContainer . id = 'teleport5'
486
- teleportContainer . innerHTML = `<div><!--teleport start--><!--teleport end--></div><!--teleport anchor--><div>child</div><!--teleport anchor-->`
492
+ teleportContainer . innerHTML = `<!--teleport start anchor-->< div><!--teleport start--><!--teleport end--></div><!--teleport anchor--><!--teleport start anchor--><div>child</div><!--teleport anchor-->`
487
493
document . body . appendChild ( teleportContainer )
488
494
489
495
const { vnode, container } = mountWithHydration (
@@ -498,7 +504,7 @@ describe('SSR hydration', () => {
498
504
expect ( vnode . anchor ) . toBe ( container . lastChild )
499
505
500
506
const childDivVNode = ( vnode as any ) . children [ 0 ]
501
- const div = teleportContainer . firstChild
507
+ const div = teleportContainer . childNodes [ 1 ]
502
508
expect ( childDivVNode . el ) . toBe ( div )
503
509
expect ( vnode . targetAnchor ) . toBe ( div ?. nextSibling )
504
510
@@ -548,6 +554,66 @@ describe('SSR hydration', () => {
548
554
teleportContainer . id = 'target'
549
555
document . body . appendChild ( teleportContainer )
550
556
557
+ // server render
558
+ const ctx : SSRContext = { }
559
+ container . innerHTML = await renderToString ( h ( App ) , ctx )
560
+ expect ( container . innerHTML ) . toBe (
561
+ '<div><!--teleport start--><!--teleport end--></div>' ,
562
+ )
563
+ teleportContainer . innerHTML = ctx . teleports ! [ '#target' ]
564
+
565
+ // hydrate
566
+ createSSRApp ( App ) . mount ( container )
567
+ expect ( container . innerHTML ) . toBe (
568
+ '<div><!--teleport start--><!--teleport end--></div>' ,
569
+ )
570
+ expect ( teleportContainer . innerHTML ) . toBe (
571
+ '<!--teleport start anchor--><span>Teleported Comp1</span><!--teleport anchor-->' ,
572
+ )
573
+ expect ( `Hydration children mismatch` ) . not . toHaveBeenWarned ( )
574
+
575
+ toggle . value = false
576
+ await nextTick ( )
577
+ expect ( container . innerHTML ) . toBe ( '<div><div>Comp2</div></div>' )
578
+ expect ( teleportContainer . innerHTML ) . toBe ( '' )
579
+ } )
580
+
581
+ test ( 'Teleport unmount (mismatch + full integration)' , async ( ) => {
582
+ const Comp1 = {
583
+ template : `
584
+ <Teleport to="#target">
585
+ <span>Teleported Comp1</span>
586
+ </Teleport>
587
+ ` ,
588
+ }
589
+ const Comp2 = {
590
+ template : `
591
+ <div>Comp2</div>
592
+ ` ,
593
+ }
594
+
595
+ const toggle = ref ( true )
596
+ const App = {
597
+ template : `
598
+ <div>
599
+ <Comp1 v-if="toggle"/>
600
+ <Comp2 v-else/>
601
+ </div>
602
+ ` ,
603
+ components : {
604
+ Comp1,
605
+ Comp2,
606
+ } ,
607
+ setup ( ) {
608
+ return { toggle }
609
+ } ,
610
+ }
611
+
612
+ const container = document . createElement ( 'div' )
613
+ const teleportContainer = document . createElement ( 'div' )
614
+ teleportContainer . id = 'target'
615
+ document . body . appendChild ( teleportContainer )
616
+
551
617
// server render
552
618
container . innerHTML = await renderToString ( h ( App ) )
553
619
expect ( container . innerHTML ) . toBe (
@@ -569,7 +635,7 @@ describe('SSR hydration', () => {
569
635
expect ( teleportContainer . innerHTML ) . toBe ( '' )
570
636
} )
571
637
572
- test ( 'Teleport target change (full integration)' , async ( ) => {
638
+ test ( 'Teleport target change (mismatch + full integration)' , async ( ) => {
573
639
const target = ref ( '#target1' )
574
640
const Comp = {
575
641
template : `
0 commit comments