From dd4b3eaf5fff8e99319f04584b60806b85cc6230 Mon Sep 17 00:00:00 2001 From: likui <2218301630@qq.com> Date: Fri, 24 Jul 2020 20:07:13 +0800 Subject: [PATCH] fix(runtime-core): should call transition hooks when suspense is resolved fix #1689 --- packages/runtime-core/src/renderer.ts | 7 +- packages/vue/__tests__/Transition.spec.ts | 149 ++++++++++++++++++++++ 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index b128d74a7f5..09f2ab242b4 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -744,9 +744,12 @@ function baseCreateRenderer( } hostInsert(el, container, anchor) - // #1583 For inside suspense case, enter hook should call when suspense resolved + // #1583 For inside suspense + suspense not resolved case, enter hook should call when suspense resolved + // #1689 For inside suspense + suspense resolved case, just call it const needCallTransitionHooks = - !parentSuspense && transition && !transition.persisted + (!parentSuspense || (parentSuspense && parentSuspense!.isResolved)) && + transition && + !transition.persisted if ( (vnodeHook = props && props.onVnodeMounted) || needCallTransitionHooks || diff --git a/packages/vue/__tests__/Transition.spec.ts b/packages/vue/__tests__/Transition.spec.ts index 95b318456f9..112e7400cf3 100644 --- a/packages/vue/__tests__/Transition.spec.ts +++ b/packages/vue/__tests__/Transition.spec.ts @@ -1100,6 +1100,155 @@ describe('e2e: Transition', () => { ) }) + describe('transition with Suspense', () => { + // #1583 + test( + 'async component transition inside Suspense', + async () => { + const onLeaveSpy = jest.fn() + const onEnterSpy = jest.fn() + + await page().exposeFunction('onLeaveSpy', onLeaveSpy) + await page().exposeFunction('onEnterSpy', onEnterSpy) + + await page().evaluate(() => { + const { onEnterSpy, onLeaveSpy } = window as any + const { createApp, ref, h } = (window as any).Vue + createApp({ + template: ` +
+ + + content + + +
+ + `, + components: { + Comp: { + async setup() { + return () => h('div', { class: 'test' }, 'content') + } + } + }, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click, onEnterSpy, onLeaveSpy } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-from' + ]) + expect(onLeaveSpy).toBeCalledTimes(1) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + const enterClass = await page().evaluate(async () => { + (document.querySelector('#toggleBtn') as any)!.click() + // nextTrick for patch start + await Promise.resolve() + // nextTrick for Suspense resolve + await Promise.resolve() + // nextTrick for dom transition start + await Promise.resolve() + return document + .querySelector('#container div')! + .className.split(/\s+/g) + }) + expect(enterClass).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-from' + ]) + expect(onEnterSpy).toBeCalledTimes(1) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + + // #1689 + test( + 'static node transition inside Suspense', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ + +
content
+
+
+
+ + `, + setup: () => { + const toggle = ref(true) + const click = () => (toggle.value = !toggle.value) + return { toggle, click } + } + }).mount('#app') + }) + expect(await html('#container')).toBe('
content
') + + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-leave-active', + 'v-leave-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-from' + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'v-enter-active', + 'v-enter-to' + ]) + await transitionFinish() + expect(await html('#container')).toBe('
content
') + }, + E2E_TIMEOUT + ) + }) + describe('transition with v-show', () => { test( 'named transition with v-show',