@@ -1427,9 +1427,11 @@ describe('e2e: Transition', () => {
14271427 } ,
14281428 E2E_TIMEOUT ,
14291429 )
1430+ } )
14301431
1432+ describe ( 'transition with KeepAlive' , ( ) => {
14311433 test (
1432- 'w/ KeepAlive + unmount innerChild' ,
1434+ 'unmount innerChild (out-in mode) ' ,
14331435 async ( ) => {
14341436 const unmountSpy = vi . fn ( )
14351437 await page ( ) . exposeFunction ( 'unmountSpy' , unmountSpy )
@@ -1484,6 +1486,173 @@ describe('e2e: Transition', () => {
14841486 } ,
14851487 E2E_TIMEOUT ,
14861488 )
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+ )
14871656 } )
14881657
14891658 describe ( 'transition with Suspense' , ( ) => {
0 commit comments