wip: add vapor transition e2e tests

This commit is contained in:
daiwei 2025-03-06 17:40:52 +08:00
parent 41c258903e
commit b65db59169
9 changed files with 325 additions and 0 deletions

View File

@ -0,0 +1,238 @@
import path from 'node:path'
import {
E2E_TIMEOUT,
setupPuppeteer,
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
import connect from 'connect'
import sirv from 'sirv'
const {
page,
click,
classList,
text,
nextFrame,
timeout,
isVisible,
count,
html,
} = setupPuppeteer()
const duration = process.env.CI ? 200 : 50
const buffer = process.env.CI ? 50 : 20
const transitionFinish = (time = duration) => timeout(time + buffer)
describe('vapor transition', () => {
let server: any
const port = '8195'
beforeAll(() => {
server = connect()
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
.listen(port)
process.on('SIGTERM', () => server && server.close())
})
afterAll(() => {
server.close()
})
beforeEach(async () => {
const baseUrl = `http://localhost:${port}/transition/`
await page().goto(baseUrl)
await page().waitForSelector('#app')
})
const classWhenTransitionStart = async (
btnSelector: string,
containerSelector: string,
) => {
return page().evaluate(
([btnSel, containerSel]) => {
;(document.querySelector(btnSel) as HTMLElement)!.click()
return Promise.resolve().then(() => {
return document.querySelector(containerSel)!.className.split(/\s+/g)
})
},
[btnSelector, containerSelector],
)
}
test(
'should work with v-show',
async () => {
const btnSelector = '.vshow > button'
const containerSelector = '.vshow > h1'
expect(await text(containerSelector)).toContain('vShow')
// leave
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-leave-from', 'v-leave-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-leave-active',
'v-leave-to',
])
await transitionFinish()
expect(await isVisible(containerSelector)).toBe(false)
// enter
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-enter-from', 'v-enter-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-enter-active',
'v-enter-to',
])
await transitionFinish()
expect(await isVisible(containerSelector)).toBe(true)
},
E2E_TIMEOUT,
)
test(
'should work with v-if + appear',
async () => {
const btnSelector = '.vif > button'
const containerSelector = '.vif > h1'
// appear
expect(await classList(containerSelector)).toStrictEqual([
'v-enter-from',
'v-enter-active',
])
expect(await text(containerSelector)).toContain('vIf')
await transitionFinish()
// leave
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-leave-from', 'v-leave-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-leave-active',
'v-leave-to',
])
await transitionFinish()
expect(await count(containerSelector)).toBe(0)
// enter
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-enter-from', 'v-enter-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-enter-active',
'v-enter-to',
])
await transitionFinish()
expect(await isVisible(containerSelector)).toBe(true)
},
E2E_TIMEOUT,
)
test(
'should work with keyed element',
async () => {
const btnSelector = '.keyed > button'
const containerSelector = '.keyed > h1'
expect(await text(containerSelector)).toContain('0')
// change key
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-leave-from', 'v-leave-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-leave-active',
'v-leave-to',
])
await transitionFinish()
expect(await text(containerSelector)).toContain('1')
// change key again
expect(
await classWhenTransitionStart(btnSelector, containerSelector),
).toStrictEqual(['v-leave-from', 'v-leave-active'])
await nextFrame()
expect(await classList(containerSelector)).toStrictEqual([
'v-leave-active',
'v-leave-to',
])
await transitionFinish()
expect(await text(containerSelector)).toContain('2')
},
E2E_TIMEOUT,
)
test(
'should work with out-in mode',
async () => {
const btnSelector = '.out-in > button'
const containerSelector = '.out-in > div'
expect(await html(containerSelector)).toBe(`<div>vapor compB</div>`)
// compB -> compA
await click(btnSelector)
expect(await html(containerSelector)).toBe(
`<div class="fade-leave-from fade-leave-active">vapor compB</div>`,
)
await nextFrame()
expect(await html(containerSelector)).toBe(
`<div class="fade-leave-active fade-leave-to">vapor compB</div>`,
)
await transitionFinish()
await nextFrame()
expect(await html(containerSelector)).toBe(
`<div class="fade-enter-active fade-enter-to">vapor compA</div>`,
)
await transitionFinish()
expect(await html(containerSelector)).toBe(
`<div class="">vapor compA</div>`,
)
// compA -> compB
await click(btnSelector)
expect(await html(containerSelector)).toBe(
`<div class="fade-leave-from fade-leave-active">vapor compA</div>`,
)
await nextFrame()
expect(await html(containerSelector)).toBe(
`<div class="fade-leave-active fade-leave-to">vapor compA</div>`,
)
await transitionFinish()
await nextFrame()
expect(await html(containerSelector)).toBe(
`<div class="fade-enter-active fade-enter-to">vapor compB</div>`,
)
await transitionFinish()
expect(await html(containerSelector)).toBe(
`<div class="">vapor compB</div>`,
)
},
E2E_TIMEOUT,
)
test.todo('should work with in-out mode', async () => {}, E2E_TIMEOUT)
})

View File

@ -1,2 +1,3 @@
<a href="/interop/">VDOM / Vapor interop</a>
<a href="/todomvc/">Vapor TodoMVC</a>
<a href="/transition/">Vapor Transition</a>

View File

@ -0,0 +1,47 @@
<script vapor>
import { ref, shallowRef } from 'vue'
const show = ref(true)
const toggle = ref(true)
const count = ref(0)
import VaporCompA from './components/VaporCompA.vue'
import VaporCompB from './components/VaporCompB.vue'
const activeComponent = shallowRef(VaporCompA)
function toggleComponent() {
activeComponent.value = activeComponent.value === VaporCompA ? VaporCompB : VaporCompA
}
</script>
<template>
<div class="vshow">
<button @click="show = !show">Show</button>
<Transition>
<h1 v-show="show">vShow</h1>
</Transition>
</div>
<div class="vif">
<button @click="toggle = !toggle">Toggle</button>
<Transition appear>
<h1 v-if="toggle">vIf</h1>
</Transition>
</div>
<div class="keyed">
<button @click="count++">inc</button>
<Transition>
<h1 style="position: absolute" :key="count">{{ count }}</h1>
</Transition>
</div>
<div class="out-in">
<button @click="toggleComponent">toggle component</button>
<div>
<Transition name="fade" mode="out-in">
<component :is="activeComponent"></component>
</Transition>
</div>
</div>
</template>
<style>
.keyed {
height: 100px
}
</style>

View File

@ -0,0 +1,6 @@
<script vapor>
const msg = 'vapor compB'
</script>
<template>
<div>{{ msg }}</div>
</template>

View File

@ -0,0 +1,6 @@
<script vapor>
const msg = 'vapor compA'
</script>
<template>
<div>{{ msg }}</div>
</template>

View File

@ -0,0 +1,2 @@
<script type="module" src="./main.ts"></script>
<div id="app"></div>

View File

@ -0,0 +1,5 @@
import { createVaporApp } from 'vue'
import App from './App.vue'
import './style.css'
createVaporApp(App).mount('#app')

View File

@ -0,0 +1,19 @@
.v-enter-active,
.v-leave-active {
transition: opacity 50ms ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 50ms ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}

View File

@ -14,6 +14,7 @@ export default defineConfig({
input: {
interop: resolve(import.meta.dirname, 'interop/index.html'),
todomvc: resolve(import.meta.dirname, 'todomvc/index.html'),
transition: resolve(import.meta.dirname, 'transition/index.html'),
},
},
},