fix(transition): should call transition hooks inside already resolved suspense (#1698)
fix #1689
This commit is contained in:
		
							parent
							
								
									6efb2fe3ea
								
							
						
					
					
						commit
						2a633c84ff
					
				@ -744,9 +744,12 @@ function baseCreateRenderer(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hostInsert(el, container, anchor)
 | 
					    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 =
 | 
					    const needCallTransitionHooks =
 | 
				
			||||||
      !parentSuspense && transition && !transition.persisted
 | 
					      (!parentSuspense || (parentSuspense && parentSuspense!.isResolved)) &&
 | 
				
			||||||
 | 
					      transition &&
 | 
				
			||||||
 | 
					      !transition.persisted
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
      (vnodeHook = props && props.onVnodeMounted) ||
 | 
					      (vnodeHook = props && props.onVnodeMounted) ||
 | 
				
			||||||
      needCallTransitionHooks ||
 | 
					      needCallTransitionHooks ||
 | 
				
			||||||
 | 
				
			|||||||
@ -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', () => {
 | 
					  describe('transition with v-show', () => {
 | 
				
			||||||
    test(
 | 
					    test(
 | 
				
			||||||
      'named transition with v-show',
 | 
					      'named transition with v-show',
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user