]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(transition): should call transition hooks inside already resolved suspense (...
authorunderfin <2218301630@qq.com>
Mon, 27 Jul 2020 20:47:07 +0000 (04:47 +0800)
committerGitHub <noreply@github.com>
Mon, 27 Jul 2020 20:47:07 +0000 (16:47 -0400)
fix #1689

packages/runtime-core/src/renderer.ts
packages/vue/__tests__/Transition.spec.ts

index b128d74a7f57ec27d9b658821707a79fba0a0884..09f2ab242b4cb2493faf7d2fb2c5bf8aebd05358 100644 (file)
@@ -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 ||
index 95b318456f98c0114542220cd07b671adf94971a..112e7400cf378eec42ca29e51a4734ba4fba245a 100644 (file)
@@ -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: `
+            <div id="container">
+              <Suspense>
+                <transition @enter="onEnterSpy"
+                            @leave="onLeaveSpy">
+                  <Comp v-if="toggle" class="test">content</Comp>
+                </transition>
+              </Suspense>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            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('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+
+    // #1689
+    test(
+      'static node transition inside Suspense',
+      async () => {
+        await page().evaluate(() => {
+          const { createApp, ref } = (window as any).Vue
+          createApp({
+            template: `
+            <div id="container">
+              <Suspense>
+                <transition>
+                  <div v-if="toggle" class="test">content</div>
+                </transition>
+              </Suspense>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const toggle = ref(true)
+              const click = () => (toggle.value = !toggle.value)
+              return { toggle, click }
+            }
+          }).mount('#app')
+        })
+        expect(await html('#container')).toBe('<div class="test">content</div>')
+
+        // 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('<!--v-if-->')
+
+        // 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('<div class="test">content</div>')
+      },
+      E2E_TIMEOUT
+    )
+  })
+
   describe('transition with v-show', () => {
     test(
       'named transition with v-show',