wip: port tests and fix bugs

This commit is contained in:
daiwei 2025-03-13 14:51:52 +08:00
parent 055ca98701
commit b1b11c7de2
3 changed files with 182 additions and 54 deletions

View File

@ -349,8 +349,55 @@ describe('vapor transition', () => {
E2E_TIMEOUT,
)
test.todo('onEnterCancelled', async () => {}, E2E_TIMEOUT)
test.todo('transition on appear', async () => {}, E2E_TIMEOUT)
test(
'onEnterCancelled',
async () => {
const btnSelector = '.if-enter-cancelled > button'
const containerSelector = '.if-enter-cancelled > div'
const childSelector = `${containerSelector} > div`
expect(await html(containerSelector)).toBe('')
// enter
expect(
(await transitionStart(btnSelector, childSelector)).classNames,
).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
await nextFrame()
expect(await classList(childSelector)).toStrictEqual([
'test',
'test-enter-active',
'test-enter-to',
])
// cancel (leave)
expect(
(await transitionStart(btnSelector, childSelector)).classNames,
).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
let calls = await page().evaluate(() => {
return (window as any).getCalls('enterCancel')
})
expect(calls).toStrictEqual(['enterCancelled'])
await nextFrame()
expect(await classList(childSelector)).toStrictEqual([
'test',
'test-leave-active',
'test-leave-to',
])
await transitionFinish()
expect(await html(containerSelector)).toBe('')
},
E2E_TIMEOUT,
)
test.todo(
'transition on appear',
async () => {
const btnSelector = '.if-appear > button'
const containerSelector = '.if-appear > div'
const childSelector = `${containerSelector} > div`
},
E2E_TIMEOUT,
)
test.todo('transition events with appear', async () => {}, E2E_TIMEOUT)
test.todo('no transition detected', async () => {}, E2E_TIMEOUT)
test.todo('animations', async () => {}, E2E_TIMEOUT)

View File

@ -4,13 +4,16 @@ const show = ref(true)
const toggle = ref(true)
const count = ref(0)
const timeout = (fn, time) => setTimeout(fn, time)
let calls = {
basic: [],
withOutAppear: [],
withArgs: []
withArgs: [],
enterCancel: [],
}
window.getCalls = (key) => calls[key]
window.resetCalls = (key) => calls[key] = []
window.getCalls = key => calls[key]
window.resetCalls = key => (calls[key] = [])
import VaporCompA from './components/VaporCompA.vue'
import VaporCompB from './components/VaporCompB.vue'
@ -52,8 +55,14 @@ const name = ref('test')
</div>
<div class="if-custom-classes">
<div>
<transition enter-from-class="hello-from" enter-active-class="hello-active" enter-to-class="hello-to"
leave-from-class="bye-from" leave-active-class="bye-active" leave-to-class="bye-to">
<transition
enter-from-class="hello-from"
enter-active-class="hello-active"
enter-to-class="hello-to"
leave-from-class="bye-from"
leave-active-class="bye-active"
leave-to-class="bye-to"
>
<div v-if="toggle" class="test">content</div>
</transition>
</div>
@ -70,10 +79,15 @@ const name = ref('test')
</div>
<div class="if-events-without-appear">
<div>
<transition name="test" @before-enter="() => calls.withOutAppear.push('beforeEnter')"
@enter="() => calls.withOutAppear.push('onEnter')" @after-enter="() => calls.withOutAppear.push('afterEnter')"
<transition
name="test"
@before-enter="() => calls.withOutAppear.push('beforeEnter')"
@enter="() => calls.withOutAppear.push('onEnter')"
@after-enter="() => calls.withOutAppear.push('afterEnter')"
@beforeLeave="() => calls.withOutAppear.push('beforeLeave')"
@leave="() => calls.withOutAppear.push('onLeave')" @afterLeave="() => calls.withOutAppear.push('afterLeave')">
@leave="() => calls.withOutAppear.push('onLeave')"
@afterLeave="() => calls.withOutAppear.push('afterLeave')"
>
<div v-if="toggle" class="test">content</div>
</transition>
</div>
@ -81,31 +95,81 @@ const name = ref('test')
</div>
<div class="if-events-with-args">
<div id="container">
<transition :css="false" name="test" @before-enter="(el) => {
calls.withArgs.push('beforeEnter');
el.classList.add('before-enter')
}" @enter="(el, done) => {
calls.withArgs.push('onEnter');
el.classList.add('enter')
setTimeout(done, 200)
}" @after-enter="(el) => {
calls.withArgs.push('afterEnter');
el.classList.add('after-enter')
}" @before-leave="(el) => {
calls.withArgs.push('beforeLeave');
el.classList.add('before-leave')
}" @leave="(el, done) => {
calls.withArgs.push('onLeave');
el.classList.add('leave')
setTimeout(done, 200)
}" @after-leave="() => {
calls.withArgs.push('afterLeave');
}">
<transition
:css="false"
name="test"
@before-enter="
el => {
calls.withArgs.push('beforeEnter')
el.classList.add('before-enter')
}
"
@enter="
(el, done) => {
calls.withArgs.push('onEnter')
el.classList.add('enter')
timeout(done, 200)
}
"
@after-enter="
el => {
calls.withArgs.push('afterEnter')
el.classList.add('after-enter')
}
"
@before-leave="
el => {
calls.withArgs.push('beforeLeave')
el.classList.add('before-leave')
}
"
@leave="
(el, done) => {
calls.withArgs.push('onLeave')
el.classList.add('leave')
timeout(done, 200)
}
"
@after-leave="
() => {
calls.withArgs.push('afterLeave')
}
"
>
<div v-if="toggle" class="test">content</div>
</transition>
</div>
<button id="toggleBtn" @click="toggle = !toggle">button</button>
</div>
<div class="if-enter-cancelled">
<div>
<transition
name="test"
@enter-cancelled="
() => {
calls.enterCancel.push('enterCancelled')
}
"
>
<div v-if="!toggle" class="test">content</div>
</transition>
</div>
<button @click="toggle = !toggle">cancelled</button>
</div>
<div class="if-appear">
<div>
<transition
name="test"
appear
appear-from-class="test-appear-from"
appear-to-class="test-appear-to"
appear-active-class="test-appear-active"
>
<div v-if="toggle" class="test">content</div>
</transition>
</div>
<button @click="toggle = !toggle">button</button>
</div>
<div class="vshow">
<button @click="show = !show">Show</button>
@ -115,11 +179,18 @@ const name = ref('test')
</div>
<div class="vif">
<button @click="toggle = !toggle">Toggle</button>
<Transition appear @beforeEnter="() => calls.basic.push('beforeEnter')" @enter="() => calls.basic.push('onEnter')"
@afterEnter="() => calls.basic.push('afterEnter')" @beforeLeave="() => calls.basic.push('beforeLeave')"
@leave="() => calls.basic.push('onLeave')" @afterLeave="() => calls.basic.push('afterLeave')"
@beforeAppear="() => calls.basic.push('beforeAppear')" @appear="() => calls.basic.push('onAppear')"
@afterAppear="() => calls.basic.push('afterAppear')">
<Transition
appear
@beforeEnter="() => calls.basic.push('beforeEnter')"
@enter="() => calls.basic.push('onEnter')"
@afterEnter="() => calls.basic.push('afterEnter')"
@beforeLeave="() => calls.basic.push('beforeLeave')"
@leave="() => calls.basic.push('onLeave')"
@afterLeave="() => calls.basic.push('afterLeave')"
@beforeAppear="() => calls.basic.push('beforeAppear')"
@appear="() => calls.basic.push('onAppear')"
@afterAppear="() => calls.basic.push('afterAppear')"
>
<h1 v-if="toggle">vIf</h1>
</Transition>
</div>
@ -182,7 +253,7 @@ const name = ref('test')
}
</style>
<style>
.transition-container>div {
.transition-container > div {
padding: 15px;
border: 1px solid #f7f7f7;
margin-top: 15px;

View File

@ -41,18 +41,23 @@ export const VaporTransition: FunctionalComponent<TransitionProps> =
checkTransitionMode(mode)
let resolvedProps
let isMounted = false
renderEffect(() => {
resolvedProps = resolveTransitionProps(props)
// only update props for Fragment block, for later reusing
if (isFragment(children) && children.$transition) {
children.$transition.props = resolvedProps
} else {
// replace existing transition hooks
const child = findTransitionBlock(children)
if (child && child.$transition) {
child.$transition.props = resolvedProps
applyTransitionHooks(child, child.$transition)
if (isMounted) {
// only update props for Fragment block, for later reusing
if (isFragment(children)) {
if (children.$transition) children.$transition.props = resolvedProps
} else {
// replace existing transition hooks
const child = findTransitionBlock(children)
if (child && child.$transition) {
child.$transition.props = resolvedProps
applyTransitionHooks(child, child.$transition)
}
}
} else {
isMounted = true
}
})
@ -133,8 +138,13 @@ export function applyTransitionHooks(
block: Block,
hooks: VaporTransitionHooks,
): VaporTransitionHooks {
const child = findTransitionBlock(block)
if (!child) return hooks
const inFragment = isFragment(block)
const child = findTransitionBlock(block, inFragment)
if (!child) {
// set transition hooks on fragment for reusing during it's updating
if (inFragment) setTransitionHooksToFragment(block, hooks)
return hooks
}
const { props, state, delayedLeave } = hooks
let resolvedHooks = resolveTransitionHooks(
@ -146,10 +156,7 @@ export function applyTransitionHooks(
)
resolvedHooks.delayedLeave = delayedLeave
setTransitionHooks(child, resolvedHooks)
if (isFragment(block)) {
// also set transition hooks on fragment for reusing during it's updating
setTransitionHooksToFragment(block, resolvedHooks)
}
if (inFragment) setTransitionHooksToFragment(block, resolvedHooks)
return resolvedHooks
}
@ -203,7 +210,10 @@ export function applyTransitionLeaveHooks(
}
const transitionBlockCache = new WeakMap<Block, TransitionBlock>()
export function findTransitionBlock(block: Block): TransitionBlock | undefined {
export function findTransitionBlock(
block: Block,
inFragment: boolean = false,
): TransitionBlock | undefined {
if (transitionBlockCache.has(block)) {
return transitionBlockCache.get(block)
}
@ -238,11 +248,11 @@ export function findTransitionBlock(block: Block): TransitionBlock | undefined {
if (block.insert) {
child = block
} else {
child = findTransitionBlock(block.nodes)
child = findTransitionBlock(block.nodes, true)
}
}
if (__DEV__ && !child) {
if (__DEV__ && !child && !inFragment) {
warn('Transition component has no valid child element')
}