@@ -3121,4 +3121,124 @@ describe('e2e: Transition', () => {
31213121 } ,
31223122 E2E_TIMEOUT ,
31233123 )
3124+
3125+ // https://github.com/vuejs/core/issues/12181#issuecomment-2414380955
3126+ describe ( 'not leaking' , async ( ) => {
3127+ test ( 'switching VNodes' , async ( ) => {
3128+ const client = await page ( ) . createCDPSession ( )
3129+ await page ( ) . evaluate ( async ( ) => {
3130+ const { createApp, ref, nextTick } = ( window as any ) . Vue
3131+ const empty = ref ( true )
3132+
3133+ createApp ( {
3134+ components : {
3135+ Child : {
3136+ setup : ( ) => {
3137+ // Big arrays kick GC earlier
3138+ const test = ref ( [ ...Array ( 30_000_000 ) ] . map ( ( _ , i ) => ( { i } ) ) )
3139+ // TODO: Use a diferent TypeScript env for testing
3140+ // @ts -expect-error - Custom property and same lib as runtime is used
3141+ window . __REF__ = new WeakRef ( test )
3142+
3143+ return { test }
3144+ } ,
3145+ template : `
3146+ <p>{{ test.length }}</p>
3147+ ` ,
3148+ } ,
3149+ Empty : {
3150+ template : '<div></div>' ,
3151+ } ,
3152+ } ,
3153+ template : `
3154+ <transition>
3155+ <component :is="empty ? 'Empty' : 'Child'" />
3156+ </transition>
3157+ ` ,
3158+ setup ( ) {
3159+ return { empty }
3160+ } ,
3161+ } ) . mount ( '#app' )
3162+
3163+ await nextTick ( )
3164+ empty . value = false
3165+ await nextTick ( )
3166+ empty . value = true
3167+ await nextTick ( )
3168+ } )
3169+
3170+ const isCollected = async ( ) =>
3171+ // @ts -expect-error - Custom property
3172+ await page ( ) . evaluate ( ( ) => window . __REF__ . deref ( ) === undefined )
3173+
3174+ while ( ( await isCollected ( ) ) === false ) {
3175+ await client . send ( 'HeapProfiler.collectGarbage' )
3176+ }
3177+
3178+ expect ( await isCollected ( ) ) . toBe ( true )
3179+ } )
3180+
3181+ // https://github.com/vuejs/core/issues/12181#issue-2588232334
3182+ test ( 'switching deep vnodes edge case' , async ( ) => {
3183+ const client = await page ( ) . createCDPSession ( )
3184+ await page ( ) . evaluate ( async ( ) => {
3185+ const { createApp, ref, nextTick } = ( window as any ) . Vue
3186+ const shown = ref ( false )
3187+
3188+ createApp ( {
3189+ components : {
3190+ Child : {
3191+ setup : ( ) => {
3192+ // Big arrays kick GC earlier
3193+ const test = ref ( [ ...Array ( 30_000_000 ) ] . map ( ( _ , i ) => ( { i } ) ) )
3194+ // TODO: Use a diferent TypeScript env for testing
3195+ // @ts -expect-error - Custom property and same lib as runtime is used
3196+ window . __REF__ = new WeakRef ( test )
3197+
3198+ return { test }
3199+ } ,
3200+ template : `
3201+ <p>{{ test.length }}</p>
3202+ ` ,
3203+ } ,
3204+ Wrapper : {
3205+ template : `
3206+ <transition>
3207+ <div v-if="true">
3208+ <slot />
3209+ </div>
3210+ </transition>
3211+ ` ,
3212+ } ,
3213+ } ,
3214+ template : `
3215+ <button id="toggleBtn" @click="shown = !shown">{{ shown ? 'Hide' : 'Show' }}</button>
3216+ <Wrapper>
3217+ <Child v-if="shown" />
3218+ <div v-else></div>
3219+ </Wrapper>
3220+ ` ,
3221+ setup ( ) {
3222+ return { shown }
3223+ } ,
3224+ } ) . mount ( '#app' )
3225+
3226+ await nextTick ( )
3227+ shown . value = true
3228+ await nextTick ( )
3229+ shown . value = false
3230+ await nextTick ( )
3231+ } )
3232+
3233+ const isCollected = async ( ) =>
3234+ // @ts -expect-error - Custom property
3235+ await page ( ) . evaluate ( ( ) => window . __REF__ . deref ( ) === undefined )
3236+
3237+ while ( ( await isCollected ( ) ) === false ) {
3238+ await client . send ( 'HeapProfiler.collectGarbage' )
3239+ }
3240+
3241+ expect ( await isCollected ( ) ) . toBe ( true )
3242+ } )
3243+ } )
31243244} )
0 commit comments