From 43be5c6de296a3dc03517e553d740468d96de34d Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 29 Apr 2024 13:35:00 +0800 Subject: [PATCH 1/3] fix(Transition): re-fix #10620 --- .../components/BaseTransition.spec.ts | 37 ------------ .../src/components/BaseTransition.ts | 2 +- .../runtime-core/src/components/KeepAlive.ts | 2 +- packages/vue/__tests__/e2e/Transition.spec.ts | 58 +++++++++++++++++++ 4 files changed, 60 insertions(+), 39 deletions(-) diff --git a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts index 1923d161897..aaeae3fb4f0 100644 --- a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts +++ b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts @@ -7,7 +7,6 @@ import { h, nextTick, nodeOps, - onUnmounted, ref, render, serialize, @@ -769,42 +768,6 @@ describe('BaseTransition', () => { test('w/ KeepAlive', async () => { await runTestWithKeepAlive(testOutIn) }) - - test('w/ KeepAlive + unmount innerChild', async () => { - const unmountSpy = vi.fn() - const includeRef = ref(['TrueBranch']) - const trueComp = { - name: 'TrueBranch', - setup() { - onUnmounted(unmountSpy) - const count = ref(0) - return () => h('div', count.value) - }, - } - - const toggle = ref(true) - const { props } = mockProps({ mode: 'out-in' }, true /*withKeepAlive*/) - const root = nodeOps.createElement('div') - const App = { - render() { - return h(BaseTransition, props, () => { - return h( - KeepAlive, - { include: includeRef.value }, - toggle.value ? h(trueComp) : h('div'), - ) - }) - }, - } - render(h(App), root) - - // trigger toggle - toggle.value = false - includeRef.value = [] - - await nextTick() - expect(unmountSpy).toHaveBeenCalledTimes(1) - }) }) // #6835 diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 8fa272d2613..070418a19a0 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -224,7 +224,7 @@ const BaseTransitionImpl: ComponentOptions = { // update old tree's hooks in case of dynamic transition setTransitionHooks(oldInnerChild, leavingHooks) // switching between different views - if (mode === 'out-in') { + if (mode === 'out-in' && innerChild.type !== Comment) { state.isLeaving = true // return placeholder node and queue update when leave finishes leavingHooks.afterLeave = () => { diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 7697096bcd7..db6088cf5c6 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -254,7 +254,7 @@ const KeepAliveImpl: ComponentOptions = { pendingCacheKey = null if (!slots.default) { - return (current = null) + return null } const children = slots.default() diff --git a/packages/vue/__tests__/e2e/Transition.spec.ts b/packages/vue/__tests__/e2e/Transition.spec.ts index e8d6d1e049e..534e3f2b275 100644 --- a/packages/vue/__tests__/e2e/Transition.spec.ts +++ b/packages/vue/__tests__/e2e/Transition.spec.ts @@ -1,6 +1,7 @@ import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils' import path from 'node:path' import { Transition, createApp, h, nextTick, ref } from 'vue' +import { expect } from 'vitest' describe('e2e: Transition', () => { const { page, html, classList, isVisible, timeout, nextFrame, click } = @@ -1214,6 +1215,63 @@ describe('e2e: Transition', () => { }, E2E_TIMEOUT, ) + + test( + 'w/ KeepAlive + unmount innerChild', + async () => { + const unmountSpy = vi.fn() + await page().exposeFunction('unmountSpy', unmountSpy) + await page().evaluate(() => { + const { unmountSpy } = window as any + const { createApp, ref, h, onUnmounted } = (window as any).Vue + createApp({ + template: ` +
+ + + + + +
+ + `, + components: { + TrueBranch: { + name: 'TrueBranch', + setup() { + onUnmounted(unmountSpy) + const count = ref(0) + return () => h('div', count.value) + }, + }, + }, + setup: () => { + const includeRef = ref(['TrueBranch']) + const toggle = ref(true) + const click = () => { + toggle.value = !toggle.value + if (toggle.value) { + includeRef.value = ['TrueBranch'] + } else { + includeRef.value = [] + } + } + return { toggle, click, unmountSpy, includeRef } + }, + }).mount('#app') + }) + + await transitionFinish() + expect(await html('#container')).toBe('
0
') + + await click('#toggleBtn') + + await transitionFinish() + expect(await html('#container')).toBe('') + expect(unmountSpy).toBeCalledTimes(1) + }, + E2E_TIMEOUT, + ) }) describe('transition with Suspense', () => { From e049cbfe72a6ea9118a239ad4bc080332d754514 Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 29 Apr 2024 13:38:07 +0800 Subject: [PATCH 2/3] fix: clean unnecessary code --- packages/vue/__tests__/e2e/Transition.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vue/__tests__/e2e/Transition.spec.ts b/packages/vue/__tests__/e2e/Transition.spec.ts index 534e3f2b275..b2c1ba572dc 100644 --- a/packages/vue/__tests__/e2e/Transition.spec.ts +++ b/packages/vue/__tests__/e2e/Transition.spec.ts @@ -1,7 +1,6 @@ import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils' import path from 'node:path' import { Transition, createApp, h, nextTick, ref } from 'vue' -import { expect } from 'vitest' describe('e2e: Transition', () => { const { page, html, classList, isVisible, timeout, nextFrame, click } = From 9f619d263028457fbb39d5eb504cf3cb53765a19 Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 29 Apr 2024 13:41:53 +0800 Subject: [PATCH 3/3] test: update test --- packages/runtime-core/__tests__/hmr.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts index 000fbf40bf8..619147d55c1 100644 --- a/packages/runtime-core/__tests__/hmr.spec.ts +++ b/packages/runtime-core/__tests__/hmr.spec.ts @@ -356,7 +356,7 @@ describe('hot module replacement', () => { triggerEvent(root.children[1] as TestElement, 'click') await nextTick() await new Promise(r => setTimeout(r, 0)) - expect(serializeInner(root)).toBe(``) + expect(serializeInner(root)).toBe(``) expect(unmountSpy).toHaveBeenCalledTimes(1) expect(mountSpy).toHaveBeenCalledTimes(1) expect(activeSpy).toHaveBeenCalledTimes(1)