@@ -1427,9 +1427,11 @@ describe('e2e: Transition', () => {
1427
1427
} ,
1428
1428
E2E_TIMEOUT ,
1429
1429
)
1430
+ } )
1430
1431
1432
+ describe ( 'transition with KeepAlive' , ( ) => {
1431
1433
test (
1432
- 'w/ KeepAlive + unmount innerChild' ,
1434
+ 'unmount innerChild (out-in mode) ' ,
1433
1435
async ( ) => {
1434
1436
const unmountSpy = vi . fn ( )
1435
1437
await page ( ) . exposeFunction ( 'unmountSpy' , unmountSpy )
@@ -1484,6 +1486,173 @@ describe('e2e: Transition', () => {
1484
1486
} ,
1485
1487
E2E_TIMEOUT ,
1486
1488
)
1489
+
1490
+ // #11775
1491
+ test (
1492
+ 'switch child then update include (out-in mode)' ,
1493
+ async ( ) => {
1494
+ const onUpdatedSpyA = vi . fn ( )
1495
+ const onUnmountedSpyC = vi . fn ( )
1496
+
1497
+ await page ( ) . exposeFunction ( 'onUpdatedSpyA' , onUpdatedSpyA )
1498
+ await page ( ) . exposeFunction ( 'onUnmountedSpyC' , onUnmountedSpyC )
1499
+
1500
+ await page ( ) . evaluate ( ( ) => {
1501
+ const { onUpdatedSpyA, onUnmountedSpyC } = window as any
1502
+ const { createApp, ref, shallowRef, h, onUpdated, onUnmounted } = (
1503
+ window as any
1504
+ ) . Vue
1505
+ createApp ( {
1506
+ template : `
1507
+ <div id="container">
1508
+ <transition mode="out-in">
1509
+ <KeepAlive :include="includeRef">
1510
+ <component :is="current" />
1511
+ </KeepAlive>
1512
+ </transition>
1513
+ </div>
1514
+ <button id="switchToB" @click="switchToB">switchToB</button>
1515
+ <button id="switchToC" @click="switchToC">switchToC</button>
1516
+ <button id="switchToA" @click="switchToA">switchToA</button>
1517
+ ` ,
1518
+ components : {
1519
+ CompA : {
1520
+ name : 'CompA' ,
1521
+ setup ( ) {
1522
+ onUpdated ( onUpdatedSpyA )
1523
+ return ( ) => h ( 'div' , 'CompA' )
1524
+ } ,
1525
+ } ,
1526
+ CompB : {
1527
+ name : 'CompB' ,
1528
+ setup ( ) {
1529
+ return ( ) => h ( 'div' , 'CompB' )
1530
+ } ,
1531
+ } ,
1532
+ CompC : {
1533
+ name : 'CompC' ,
1534
+ setup ( ) {
1535
+ onUnmounted ( onUnmountedSpyC )
1536
+ return ( ) => h ( 'div' , 'CompC' )
1537
+ } ,
1538
+ } ,
1539
+ } ,
1540
+ setup : ( ) => {
1541
+ const includeRef = ref ( [ 'CompA' , 'CompB' , 'CompC' ] )
1542
+ const current = shallowRef ( 'CompA' )
1543
+ const switchToB = ( ) => ( current . value = 'CompB' )
1544
+ const switchToC = ( ) => ( current . value = 'CompC' )
1545
+ const switchToA = ( ) => {
1546
+ current . value = 'CompA'
1547
+ includeRef . value = [ 'CompA' ]
1548
+ }
1549
+ return { current, switchToB, switchToC, switchToA, includeRef }
1550
+ } ,
1551
+ } ) . mount ( '#app' )
1552
+ } )
1553
+
1554
+ await transitionFinish ( )
1555
+ expect ( await html ( '#container' ) ) . toBe ( '<div>CompA</div>' )
1556
+
1557
+ await click ( '#switchToB' )
1558
+ await nextTick ( )
1559
+ await click ( '#switchToC' )
1560
+ await transitionFinish ( )
1561
+ expect ( await html ( '#container' ) ) . toBe ( '<div class="">CompC</div>' )
1562
+
1563
+ await click ( '#switchToA' )
1564
+ await transitionFinish ( )
1565
+ expect ( await html ( '#container' ) ) . toBe ( '<div class="">CompA</div>' )
1566
+
1567
+ // expect CompA only update once
1568
+ expect ( onUpdatedSpyA ) . toBeCalledTimes ( 1 )
1569
+ expect ( onUnmountedSpyC ) . toBeCalledTimes ( 1 )
1570
+ } ,
1571
+ E2E_TIMEOUT ,
1572
+ )
1573
+
1574
+ // #10827
1575
+ test (
1576
+ 'switch and update child then update include (out-in mode)' ,
1577
+ async ( ) => {
1578
+ const onUnmountedSpyB = vi . fn ( )
1579
+ await page ( ) . exposeFunction ( 'onUnmountedSpyB' , onUnmountedSpyB )
1580
+
1581
+ await page ( ) . evaluate ( ( ) => {
1582
+ const { onUnmountedSpyB } = window as any
1583
+ const {
1584
+ createApp,
1585
+ ref,
1586
+ shallowRef,
1587
+ h,
1588
+ provide,
1589
+ inject,
1590
+ onUnmounted,
1591
+ } = ( window as any ) . Vue
1592
+ createApp ( {
1593
+ template : `
1594
+ <div id="container">
1595
+ <transition name="test-anim" mode="out-in">
1596
+ <KeepAlive :include="includeRef">
1597
+ <component :is="current" />
1598
+ </KeepAlive>
1599
+ </transition>
1600
+ </div>
1601
+ <button id="switchToA" @click="switchToA">switchToA</button>
1602
+ <button id="switchToB" @click="switchToB">switchToB</button>
1603
+ ` ,
1604
+ components : {
1605
+ CompA : {
1606
+ name : 'CompA' ,
1607
+ setup ( ) {
1608
+ const current = inject ( 'current' )
1609
+ return ( ) => h ( 'div' , current . value )
1610
+ } ,
1611
+ } ,
1612
+ CompB : {
1613
+ name : 'CompB' ,
1614
+ setup ( ) {
1615
+ const current = inject ( 'current' )
1616
+ onUnmounted ( onUnmountedSpyB )
1617
+ return ( ) => h ( 'div' , current . value )
1618
+ } ,
1619
+ } ,
1620
+ } ,
1621
+ setup : ( ) => {
1622
+ const includeRef = ref ( [ 'CompA' ] )
1623
+ const current = shallowRef ( 'CompA' )
1624
+ provide ( 'current' , current )
1625
+
1626
+ const switchToB = ( ) => {
1627
+ current . value = 'CompB'
1628
+ includeRef . value = [ 'CompA' , 'CompB' ]
1629
+ }
1630
+ const switchToA = ( ) => {
1631
+ current . value = 'CompA'
1632
+ includeRef . value = [ 'CompA' ]
1633
+ }
1634
+ return { current, switchToB, switchToA, includeRef }
1635
+ } ,
1636
+ } ) . mount ( '#app' )
1637
+ } )
1638
+
1639
+ await transitionFinish ( )
1640
+ expect ( await html ( '#container' ) ) . toBe ( '<div>CompA</div>' )
1641
+
1642
+ await click ( '#switchToB' )
1643
+ await transitionFinish ( )
1644
+ await transitionFinish ( )
1645
+ expect ( await html ( '#container' ) ) . toBe ( '<div class="">CompB</div>' )
1646
+
1647
+ await click ( '#switchToA' )
1648
+ await transitionFinish ( )
1649
+ await transitionFinish ( )
1650
+ expect ( await html ( '#container' ) ) . toBe ( '<div class="">CompA</div>' )
1651
+
1652
+ expect ( onUnmountedSpyB ) . toBeCalledTimes ( 1 )
1653
+ } ,
1654
+ E2E_TIMEOUT ,
1655
+ )
1487
1656
} )
1488
1657
1489
1658
describe ( 'transition with Suspense' , ( ) => {
0 commit comments