@@ -82,4 +82,65 @@ describe('not leaking', async () => {
82
82
} ,
83
83
E2E_TIMEOUT ,
84
84
)
85
+
86
+ // #13211
87
+ test (
88
+ 'cached array vnodes should not retaining detached DOM nodes' ,
89
+ async ( ) => {
90
+ const client = await page ( ) . createCDPSession ( )
91
+ await page ( ) . evaluate ( async ( ) => {
92
+ const { createApp, ref } = ( window as any ) . Vue
93
+ createApp ( {
94
+ components : {
95
+ Comp1 : {
96
+ template : `
97
+ <h1><slot></slot></h1>
98
+ <div>{{ test.length }}</div>
99
+ ` ,
100
+ setup ( ) {
101
+ const test = ref ( [ ...Array ( 3000 ) ] . map ( ( _ , i ) => ( { i } ) ) )
102
+ // @ts -expect-error
103
+ window . __REF__ = new WeakRef ( test )
104
+
105
+ return { test }
106
+ } ,
107
+ } ,
108
+ } ,
109
+ template : `
110
+ <button id="toggleBtn" @click="click">button</button>
111
+ <Comp1 v-if="toggle">slot content</Comp1>
112
+ ` ,
113
+ setup ( ) {
114
+ const toggle = ref ( true )
115
+ const click = ( ) => ( toggle . value = ! toggle . value )
116
+ return { toggle, click }
117
+ } ,
118
+ } ) . mount ( '#app' )
119
+ } )
120
+
121
+ expect ( await html ( '#app' ) ) . toBe (
122
+ `<button id="toggleBtn">button</button>` +
123
+ `<h1>` +
124
+ `slot content` +
125
+ `</h1>` +
126
+ `<div>3000</div>` ,
127
+ )
128
+
129
+ await click ( '#toggleBtn' )
130
+ expect ( await html ( '#app' ) ) . toBe (
131
+ `<button id="toggleBtn">button</button><!--v-if-->` ,
132
+ )
133
+
134
+ const isCollected = async ( ) =>
135
+ // @ts -expect-error
136
+ await page ( ) . evaluate ( ( ) => window . __REF__ . deref ( ) === undefined )
137
+
138
+ while ( ( await isCollected ( ) ) === false ) {
139
+ await client . send ( 'HeapProfiler.collectGarbage' )
140
+ }
141
+
142
+ expect ( await isCollected ( ) ) . toBe ( true )
143
+ } ,
144
+ E2E_TIMEOUT ,
145
+ )
85
146
} )
0 commit comments