).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
let calls = await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
})
expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
await nextFrame()
expect(
await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
}),
).not.contain('afterLeave')
await transitionFinish()
expect(await html(containerSelector)).toBe('')
expect(
await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
}),
).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
await page().evaluate(() => {
- ;(window as any).resetCalls('withOutAppear')
+ ;(window as any).resetCalls('withoutAppear')
})
// enter
).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
calls = await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
})
expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
await nextFrame()
])
expect(
await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
}),
).not.contain('afterEnter')
await transitionFinish()
)
expect(
await page().evaluate(() => {
- return (window as any).getCalls('withOutAppear')
+ return (window as any).getCalls('withoutAppear')
}),
).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
},
E2E_TIMEOUT,
)
- test.todo(
+ test(
'transition on appear',
async () => {
const btnSelector = '.if-appear > button'
const containerSelector = '.if-appear > div'
const childSelector = `${containerSelector} > div`
+
+ // appear
+ expect(await classList(childSelector)).contains('test-appear-active')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+ await transitionFinish()
+ 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',
+ ])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</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)
- test.todo('explicit transition type', async () => {}, E2E_TIMEOUT)
+
+ test(
+ 'transition events with appear',
+ async () => {
+ const btnSelector = '.if-events-with-appear > button'
+ const containerSelector = '.if-events-with-appear > div'
+ const childSelector = `${containerSelector} > div`
+ // appear
+ expect(await classList(childSelector)).contains('test-appear-active')
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeAppear', 'onAppear'])
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeAppear', 'onAppear', 'afterAppear'])
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withAppear')
+ })
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave'])
+
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).not.contain('afterLeave')
+
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe('')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('withAppear')
+ })
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-enter-from', 'test-enter-active'])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-enter-active',
+ 'test-enter-to',
+ ])
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).not.contain('afterEnter')
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('withAppear')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ },
+ E2E_TIMEOUT,
+ )
+ test(
+ 'css: false',
+ async () => {
+ const btnSelector = '.if-css-false > button'
+ const containerSelector = '.if-css-false > div'
+ const childSelector = `${containerSelector} > div`
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+
+ // leave
+ await click(btnSelector)
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls('cssFalse')
+ })
+ expect(calls).toStrictEqual(['beforeLeave', 'onLeave', 'afterLeave'])
+ expect(await html(containerSelector)).toBe('')
+
+ await page().evaluate(() => {
+ ;(window as any).resetCalls('cssFalse')
+ })
+
+ // enter
+ await transitionStart(btnSelector, childSelector)
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls('cssFalse')
+ })
+ expect(calls).toStrictEqual(['beforeEnter', 'onEnter', 'afterEnter'])
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'no transition detected',
+ async () => {
+ const btnSelector = '.if-no-trans > button'
+ const containerSelector = '.if-no-trans > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('<div>content</div>')
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['noop-leave-from', 'noop-leave-active'])
+ await nextFrame()
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['noop-enter-from', 'noop-enter-active'])
+ await nextFrame()
+ expect(await html(containerSelector)).toBe(
+ '<div class="">content</div>',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'animations',
+ async () => {
+ const btnSelector = '.if-ani > button'
+ const containerSelector = '.if-ani > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('<div>content</div>')
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test-anim-leave-from', 'test-anim-leave-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-leave-active',
+ 'test-anim-leave-to',
+ ])
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test-anim-enter-from', 'test-anim-enter-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-enter-active',
+ 'test-anim-enter-to',
+ ])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="">content</div>',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
+ test(
+ 'explicit transition type',
+ async () => {
+ const btnSelector = '.if-ani-explicit-type > button'
+ const containerSelector = '.if-ani-explicit-type > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('<div>content</div>')
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual([
+ 'test-anim-long-leave-from',
+ 'test-anim-long-leave-active',
+ ])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-leave-active',
+ 'test-anim-long-leave-to',
+ ])
+
+ if (!process.env.CI) {
+ await new Promise(r => {
+ setTimeout(r, duration - buffer)
+ })
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-leave-active',
+ 'test-anim-long-leave-to',
+ ])
+ }
+
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe('')
+
+ // enter
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual([
+ 'test-anim-long-enter-from',
+ 'test-anim-long-enter-active',
+ ])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-enter-active',
+ 'test-anim-long-enter-to',
+ ])
+
+ if (!process.env.CI) {
+ await new Promise(r => {
+ setTimeout(r, duration - buffer)
+ })
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test-anim-long-enter-active',
+ 'test-anim-long-enter-to',
+ ])
+ }
+
+ await transitionFinish(duration * 2)
+ expect(await html(containerSelector)).toBe(
+ '<div class="">content</div>',
+ )
+ },
+ E2E_TIMEOUT,
+ )
+
test.todo('transition on SVG elements', async () => {}, E2E_TIMEOUT)
- test.todo(
+
+ test(
'custom transition higher-order component',
- async () => {},
+ async () => {
+ const btnSelector = '.if-high-order > button'
+ const containerSelector = '.if-high-order > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+ await nextFrame()
+ expect(await classList(childSelector)).toStrictEqual([
+ 'test',
+ 'test-leave-active',
+ 'test-leave-to',
+ ])
+ await transitionFinish()
+ 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',
+ ])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">content</div>',
+ )
+ },
E2E_TIMEOUT,
)
- test.todo(
+
+ test(
'transition on child components with empty root node',
- async () => {},
+ async () => {
+ const btnSelector = '.if-empty-root > button.toggle'
+ const btnChangeSelector = '.if-empty-root > button.change'
+ const containerSelector = '.if-empty-root > div'
+ const childSelector = `${containerSelector} > div`
+
+ expect(await html(containerSelector)).toBe('')
+
+ // change view -> 'two'
+ await click(btnChangeSelector)
+
+ // 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',
+ ])
+ await transitionFinish()
+ expect(await html(containerSelector)).toBe(
+ '<div class="test">two</div>',
+ )
+
+ // change view -> 'one'
+ await click(btnChangeSelector)
+
+ // leave
+ expect(
+ (await transitionStart(btnSelector, childSelector)).classNames,
+ ).toStrictEqual(['test', 'test-leave-from', 'test-leave-active'])
+ 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 with v-if at component root-level',
async () => {},
<script vapor>
-import { ref, shallowRef } from 'vue'
+import {
+ createComponent,
+ defineVaporComponent,
+ ref,
+ shallowRef,
+ VaporTransition,
+ createIf,
+ template,
+} from 'vue'
const show = ref(true)
const toggle = ref(true)
const count = ref(0)
let calls = {
basic: [],
- withOutAppear: [],
+ withoutAppear: [],
withArgs: [],
enterCancel: [],
+ withAppear: [],
+ cssFalse: [],
}
window.getCalls = key => calls[key]
window.resetCalls = key => (calls[key] = [])
}
const name = ref('test')
+const MyTransition = defineVaporComponent((props, { slots }) => {
+ return createComponent(VaporTransition, { name: () => 'test' }, slots)
+})
+
+const One = defineVaporComponent({
+ setup() {
+ return createIf(
+ () => false,
+ () => template('<div>one</div>', true)(),
+ )
+ },
+})
+
+const Two = defineVaporComponent({
+ setup() {
+ return template('<div>two</div>', true)()
+ },
+})
+const view = shallowRef(One)
+function changeView() {
+ view.value = view.value === One ? Two : One
+}
</script>
<template>
<div>
<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')"
+ @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')"
>
<div v-if="toggle" class="test">content</div>
</transition>
<div v-if="toggle" class="test">content</div>
</transition>
</div>
- <button id="toggleBtn" @click="toggle = !toggle">button</button>
+ <button @click="toggle = !toggle">button</button>
</div>
<div class="if-enter-cancelled">
<div>
</div>
<button @click="toggle = !toggle">button</button>
</div>
+ <div class="if-events-with-appear">
+ <div>
+ <transition
+ name="test"
+ appear
+ appear-from-class="test-appear-from"
+ appear-to-class="test-appear-to"
+ appear-active-class="test-appear-active"
+ @beforeEnter="() => calls.withAppear.push('beforeEnter')"
+ @enter="() => calls.withAppear.push('onEnter')"
+ @afterEnter="() => calls.withAppear.push('afterEnter')"
+ @beforeLeave="() => calls.withAppear.push('beforeLeave')"
+ @leave="() => calls.withAppear.push('onLeave')"
+ @afterLeave="() => calls.withAppear.push('afterLeave')"
+ @beforeAppear="() => calls.withAppear.push('beforeAppear')"
+ @appear="() => calls.withAppear.push('onAppear')"
+ @afterAppear="() => calls.withAppear.push('afterAppear')"
+ >
+ <div v-if="toggle" class="test">content</div>
+ </transition>
+ </div>
+ <button @click="toggle = !toggle">button</button>
+ </div>
+ <div class="if-css-false">
+ <div>
+ <transition
+ :css="false"
+ name="test"
+ @beforeEnter="() => calls.cssFalse.push('beforeEnter')"
+ @enter="() => calls.cssFalse.push('onEnter')"
+ @afterEnter="() => calls.cssFalse.push('afterEnter')"
+ @beforeLeave="() => calls.cssFalse.push('beforeLeave')"
+ @leave="() => calls.cssFalse.push('onLeave')"
+ @afterLeave="() => calls.cssFalse.push('afterLeave')"
+ >
+ <div v-if="toggle" class="test">content</div>
+ </transition>
+ </div>
+ <button @click="toggle = !toggle"></button>
+ </div>
+ <div class="if-no-trans">
+ <div>
+ <transition name="noop">
+ <div v-if="toggle">content</div>
+ </transition>
+ </div>
+ <button @click="toggle = !toggle">button</button>
+ </div>
+ <div class="if-ani">
+ <div>
+ <transition name="test-anim">
+ <div v-if="toggle">content</div>
+ </transition>
+ </div>
+ <button @click="toggle = !toggle">button</button>
+ </div>
+ <div class="if-ani-explicit-type">
+ <div>
+ <transition name="test-anim-long" type="animation">
+ <div v-if="toggle">content</div>
+ </transition>
+ </div>
+ <button @click="toggle = !toggle">button</button>
+ </div>
+ <div class="if-high-order">
+ <div>
+ <MyTransition>
+ <div v-if="toggle" class="test">content</div>
+ </MyTransition>
+ </div>
+ <button @click="toggle = !toggle">button</button>
+ </div>
+ <div class="if-empty-root">
+ <div>
+ <transition name="test">
+ <component class="test" :is="view"></component>
+ </transition>
+ </div>
+ <button class="toggle" @click="toggle = !toggle">button</button>
+ <button class="change" @click="changeView">changeView button</button>
+ </div>
<div class="vshow">
<button @click="show = !show">Show</button>