Skip to content

Commit

Permalink
fix(transition): should call transition hooks inside already resolved…
Browse files Browse the repository at this point in the history
… suspense (#1698)

fix #1689
  • Loading branch information
underfin authored Jul 27, 2020
1 parent 6efb2fe commit 2a633c8
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 2 deletions.
7 changes: 5 additions & 2 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down
149 changes: 149 additions & 0 deletions packages/vue/__tests__/Transition.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 2a633c8

Please sign in to comment.