]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: add test case for transition memory leaks
authorEvan You <evan@vuejs.org>
Fri, 15 Nov 2024 02:50:26 +0000 (10:50 +0800)
committerEvan You <evan@vuejs.org>
Fri, 15 Nov 2024 02:50:26 +0000 (10:50 +0800)
from https://github.com/vuejs/core/pull/12190

packages/vue/__tests__/e2e/Transition.spec.ts

index c0863a75991be303db3781088c49a0a708dfd019..60274ad134cfccb1ae4f402a87744205323478c1 100644 (file)
@@ -3121,4 +3121,124 @@ describe('e2e: Transition', () => {
     },
     E2E_TIMEOUT,
   )
+
+  // https://github.com/vuejs/core/issues/12181#issuecomment-2414380955
+  describe('not leaking', async () => {
+    test('switching VNodes', async () => {
+      const client = await page().createCDPSession()
+      await page().evaluate(async () => {
+        const { createApp, ref, nextTick } = (window as any).Vue
+        const empty = ref(true)
+
+        createApp({
+          components: {
+            Child: {
+              setup: () => {
+                // Big arrays kick GC earlier
+                const test = ref([...Array(30_000_000)].map((_, i) => ({ i })))
+                // TODO: Use a diferent TypeScript env for testing
+                // @ts-expect-error - Custom property and same lib as runtime is used
+                window.__REF__ = new WeakRef(test)
+
+                return { test }
+              },
+              template: `
+                <p>{{ test.length }}</p>
+              `,
+            },
+            Empty: {
+              template: '<div></div>',
+            },
+          },
+          template: `
+            <transition>
+              <component :is="empty ? 'Empty' : 'Child'" />
+            </transition>
+          `,
+          setup() {
+            return { empty }
+          },
+        }).mount('#app')
+
+        await nextTick()
+        empty.value = false
+        await nextTick()
+        empty.value = true
+        await nextTick()
+      })
+
+      const isCollected = async () =>
+        // @ts-expect-error - Custom property
+        await page().evaluate(() => window.__REF__.deref() === undefined)
+
+      while ((await isCollected()) === false) {
+        await client.send('HeapProfiler.collectGarbage')
+      }
+
+      expect(await isCollected()).toBe(true)
+    })
+
+    // https://github.com/vuejs/core/issues/12181#issue-2588232334
+    test('switching deep vnodes edge case', async () => {
+      const client = await page().createCDPSession()
+      await page().evaluate(async () => {
+        const { createApp, ref, nextTick } = (window as any).Vue
+        const shown = ref(false)
+
+        createApp({
+          components: {
+            Child: {
+              setup: () => {
+                // Big arrays kick GC earlier
+                const test = ref([...Array(30_000_000)].map((_, i) => ({ i })))
+                // TODO: Use a diferent TypeScript env for testing
+                // @ts-expect-error - Custom property and same lib as runtime is used
+                window.__REF__ = new WeakRef(test)
+
+                return { test }
+              },
+              template: `
+                <p>{{ test.length }}</p>
+              `,
+            },
+            Wrapper: {
+              template: `
+                <transition>
+                  <div v-if="true">
+                    <slot />
+                  </div>
+                </transition>
+              `,
+            },
+          },
+          template: `
+            <button id="toggleBtn" @click="shown = !shown">{{ shown ? 'Hide' : 'Show' }}</button>
+            <Wrapper>
+              <Child v-if="shown" />
+              <div v-else></div>
+            </Wrapper>
+          `,
+          setup() {
+            return { shown }
+          },
+        }).mount('#app')
+
+        await nextTick()
+        shown.value = true
+        await nextTick()
+        shown.value = false
+        await nextTick()
+      })
+
+      const isCollected = async () =>
+        // @ts-expect-error - Custom property
+        await page().evaluate(() => window.__REF__.deref() === undefined)
+
+      while ((await isCollected()) === false) {
+        await client.send('HeapProfiler.collectGarbage')
+      }
+
+      expect(await isCollected()).toBe(true)
+    })
+  })
 })