mirror of https://github.com/vuejs/core.git
wip: add interop tests
This commit is contained in:
parent
d5d8ada577
commit
d1849288d1
|
@ -5,8 +5,18 @@ import {
|
|||
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
|
||||
import connect from 'connect'
|
||||
import sirv from 'sirv'
|
||||
const { page, classList, text, nextFrame, timeout, isVisible, count, html } =
|
||||
setupPuppeteer()
|
||||
const {
|
||||
page,
|
||||
classList,
|
||||
text,
|
||||
nextFrame,
|
||||
timeout,
|
||||
isVisible,
|
||||
count,
|
||||
html,
|
||||
transitionStart,
|
||||
waitForElement,
|
||||
} = setupPuppeteer()
|
||||
|
||||
const duration = process.env.CI ? 200 : 50
|
||||
const buffer = process.env.CI ? 50 : 20
|
||||
|
@ -32,43 +42,6 @@ describe('vapor transition', () => {
|
|||
await page().waitForSelector('#app')
|
||||
})
|
||||
|
||||
const transitionStart = (btnSelector: string, containerSelector: string) =>
|
||||
page().evaluate(
|
||||
([btnSel, containerSel]) => {
|
||||
;(document.querySelector(btnSel) as HTMLElement)!.click()
|
||||
return Promise.resolve().then(() => {
|
||||
const container = document.querySelector(containerSel)!
|
||||
return {
|
||||
classNames: container.className.split(/\s+/g),
|
||||
innerHTML: container.innerHTML,
|
||||
}
|
||||
})
|
||||
},
|
||||
[btnSelector, containerSelector],
|
||||
)
|
||||
|
||||
const waitForElement = (
|
||||
selector: string,
|
||||
text: string,
|
||||
classNames: string[], // if empty, check for no classes
|
||||
timeout = 2000,
|
||||
) =>
|
||||
page().waitForFunction(
|
||||
(sel, expectedText, expectedClasses) => {
|
||||
const el = document.querySelector(sel)
|
||||
const hasClasses =
|
||||
expectedClasses.length === 0
|
||||
? el?.classList.length === 0
|
||||
: expectedClasses.every(c => el?.classList.contains(c))
|
||||
const hasText = el?.textContent?.includes(expectedText)
|
||||
return !!el && hasClasses && hasText
|
||||
},
|
||||
{ timeout },
|
||||
selector,
|
||||
text,
|
||||
classNames,
|
||||
)
|
||||
|
||||
test(
|
||||
'should work with v-show',
|
||||
async () => {
|
||||
|
|
|
@ -5,10 +5,23 @@ import {
|
|||
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
|
||||
import connect from 'connect'
|
||||
import sirv from 'sirv'
|
||||
const {
|
||||
page,
|
||||
click,
|
||||
text,
|
||||
enterValue,
|
||||
html,
|
||||
transitionStart,
|
||||
waitForElement,
|
||||
nextFrame,
|
||||
timeout,
|
||||
} = setupPuppeteer()
|
||||
|
||||
const duration = process.env.CI ? 200 : 50
|
||||
const buffer = process.env.CI ? 50 : 20
|
||||
const transitionFinish = (time = duration) => timeout(time + buffer)
|
||||
|
||||
describe('vdom / vapor interop', () => {
|
||||
const { page, click, text, enterValue } = setupPuppeteer()
|
||||
|
||||
let server: any
|
||||
const port = '8193'
|
||||
beforeAll(() => {
|
||||
|
@ -22,12 +35,15 @@ describe('vdom / vapor interop', () => {
|
|||
server.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
const baseUrl = `http://localhost:${port}/interop/`
|
||||
await page().goto(baseUrl)
|
||||
await page().waitForSelector('#app')
|
||||
})
|
||||
|
||||
test(
|
||||
'should work',
|
||||
async () => {
|
||||
const baseUrl = `http://localhost:${port}/interop/`
|
||||
await page().goto(baseUrl)
|
||||
|
||||
expect(await text('.vapor > h2')).toContain('Vapor component in VDOM')
|
||||
|
||||
expect(await text('.vapor-prop')).toContain('hello')
|
||||
|
@ -81,4 +97,121 @@ describe('vdom / vapor interop', () => {
|
|||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
|
||||
describe('vdom transition', () => {
|
||||
test(
|
||||
'render vapor component',
|
||||
async () => {
|
||||
const btnSelector = '.trans-vapor > button'
|
||||
const containerSelector = '.trans-vapor > div'
|
||||
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div key="0">vapor compA</div>`,
|
||||
)
|
||||
|
||||
// comp leave
|
||||
expect(
|
||||
(await transitionStart(btnSelector, containerSelector)).innerHTML,
|
||||
).toBe(
|
||||
`<div key="0" class="v-leave-from v-leave-active">vapor compA</div><!---->`,
|
||||
)
|
||||
|
||||
await nextFrame()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div key="0" class="v-leave-active v-leave-to">vapor compA</div><!---->`,
|
||||
)
|
||||
|
||||
await transitionFinish()
|
||||
expect(await html(containerSelector)).toBe(`<!---->`)
|
||||
|
||||
// comp enter
|
||||
expect(
|
||||
(await transitionStart(btnSelector, containerSelector)).innerHTML,
|
||||
).toBe(
|
||||
`<div key="0" class="v-enter-from v-enter-active">vapor compA</div>`,
|
||||
)
|
||||
|
||||
await nextFrame()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div key="0" class="v-enter-active v-enter-to">vapor compA</div>`,
|
||||
)
|
||||
|
||||
await transitionFinish()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div key="0" class="">vapor compA</div>`,
|
||||
)
|
||||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
|
||||
test(
|
||||
'switch between vdom/vapor component (out-in mode)',
|
||||
async () => {
|
||||
const btnSelector = '.trans-vdom-vapor-out-in > button'
|
||||
const containerSelector = '.trans-vdom-vapor-out-in > div'
|
||||
const childSelector = `${containerSelector} > div`
|
||||
|
||||
expect(await html(containerSelector)).toBe(`<div>vdom comp</div>`)
|
||||
|
||||
// switch to vapor comp
|
||||
// vdom comp leave
|
||||
expect(
|
||||
(await transitionStart(btnSelector, containerSelector)).innerHTML,
|
||||
).toBe(
|
||||
`<div class="fade-leave-from fade-leave-active">vdom comp</div><!---->`,
|
||||
)
|
||||
|
||||
await nextFrame()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div class="fade-leave-active fade-leave-to">vdom comp</div><!---->`,
|
||||
)
|
||||
|
||||
// vapor comp enter
|
||||
await waitForElement(childSelector, 'vapor compA', [
|
||||
'fade-enter-from',
|
||||
'fade-enter-active',
|
||||
])
|
||||
|
||||
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>`,
|
||||
)
|
||||
|
||||
// switch to vdom comp
|
||||
// vapor comp leave
|
||||
expect(
|
||||
(await transitionStart(btnSelector, containerSelector)).innerHTML,
|
||||
).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><!---->`,
|
||||
)
|
||||
|
||||
// vdom comp enter
|
||||
await waitForElement(childSelector, 'vdom comp', [
|
||||
'fade-enter-from',
|
||||
'fade-enter-active',
|
||||
])
|
||||
|
||||
await nextFrame()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div class="fade-enter-active fade-enter-to">vdom comp</div>`,
|
||||
)
|
||||
|
||||
await transitionFinish()
|
||||
expect(await html(containerSelector)).toBe(
|
||||
`<div class="">vdom comp</div>`,
|
||||
)
|
||||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import VaporComp from './VaporComp.vue'
|
||||
import VaporCompA from '../transition/components/VaporCompA.vue'
|
||||
import VdomComp from '../transition/components/VdomComp.vue'
|
||||
|
||||
const msg = ref('hello')
|
||||
const passSlot = ref(true)
|
||||
|
||||
const toggleVapor = ref(true)
|
||||
const interopComponent = shallowRef(VdomComp)
|
||||
function toggleInteropComponent() {
|
||||
interopComponent.value =
|
||||
interopComponent.value === VaporCompA ? VdomComp : VaporCompA
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -19,4 +28,28 @@ const passSlot = ref(true)
|
|||
|
||||
<template #test v-if="passSlot">A test slot</template>
|
||||
</VaporComp>
|
||||
|
||||
<!-- transition interop -->
|
||||
<div>
|
||||
<div class="trans-vapor">
|
||||
<button @click="toggleVapor = !toggleVapor">
|
||||
toggle vapor component
|
||||
</button>
|
||||
<div>
|
||||
<Transition>
|
||||
<VaporCompA v-if="toggleVapor" />
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trans-vdom-vapor-out-in">
|
||||
<button @click="toggleInteropComponent">
|
||||
switch between vdom/vapor component out-in mode
|
||||
</button>
|
||||
<div>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<component :is="interopComponent"></component>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { createApp, vaporInteropPlugin } from 'vue'
|
||||
import App from './App.vue'
|
||||
import '../transition/style.css'
|
||||
|
||||
createApp(App).use(vaporInteropPlugin).mount('#app')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script vapor>
|
||||
<script setup vapor lang="ts">
|
||||
const msg = 'vapor compA'
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script vapor>
|
||||
<script setup vapor lang="ts">
|
||||
const msg = 'vapor compB'
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script setup>
|
||||
<script setup lang="ts">
|
||||
const msg = 'vdom comp'
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
type VaporTransitionHooks,
|
||||
isFragment,
|
||||
} from '../block'
|
||||
import { isVaporComponent } from '../component'
|
||||
import { type VaporComponentInstance, isVaporComponent } from '../component'
|
||||
|
||||
const decorate = (t: typeof VaporTransition) => {
|
||||
t.displayName = 'VaporTransition'
|
||||
|
@ -244,3 +244,13 @@ export function findTransitionBlock(block: Block): TransitionBlock | undefined {
|
|||
|
||||
return child
|
||||
}
|
||||
|
||||
export function setTransitionToInstance(
|
||||
block: VaporComponentInstance,
|
||||
hooks: VaporTransitionHooks,
|
||||
): void {
|
||||
const child = findTransitionBlock(block.block)
|
||||
if (!child) return
|
||||
|
||||
setTransitionHooks(child, hooks)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
ensureRenderer,
|
||||
onScopeDispose,
|
||||
renderSlot,
|
||||
setTransitionHooks,
|
||||
setTransitionHooks as setVNodeTransitionHooks,
|
||||
shallowRef,
|
||||
simpleSetCurrentInstance,
|
||||
} from '@vue/runtime-dom'
|
||||
|
@ -28,13 +28,20 @@ import {
|
|||
mountComponent,
|
||||
unmountComponent,
|
||||
} from './component'
|
||||
import { type Block, VaporFragment, insert, remove } from './block'
|
||||
import {
|
||||
type Block,
|
||||
VaporFragment,
|
||||
type VaporTransitionHooks,
|
||||
insert,
|
||||
remove,
|
||||
} from './block'
|
||||
import { EMPTY_OBJ, extend, isFunction } from '@vue/shared'
|
||||
import { type RawProps, rawPropsProxyHandlers } from './componentProps'
|
||||
import type { RawSlots, VaporSlot } from './componentSlots'
|
||||
import { renderEffect } from './renderEffect'
|
||||
import { createTextNode } from './dom/node'
|
||||
import { optimizePropertyLookup } from './dom/prop'
|
||||
import { setTransitionToInstance } from './components/Transition'
|
||||
|
||||
// mounting vapor components and slots in vdom
|
||||
const vaporInteropImpl: Omit<
|
||||
|
@ -62,6 +69,12 @@ const vaporInteropImpl: Omit<
|
|||
))
|
||||
instance.rawPropsRef = propsRef
|
||||
instance.rawSlotsRef = slotsRef
|
||||
if (vnode.transition) {
|
||||
setTransitionToInstance(
|
||||
instance,
|
||||
vnode.transition as VaporTransitionHooks,
|
||||
)
|
||||
}
|
||||
mountComponent(instance, container, selfAnchor)
|
||||
simpleSetCurrentInstance(prev)
|
||||
return instance
|
||||
|
@ -174,7 +187,7 @@ function createVDOMComponent(
|
|||
let isMounted = false
|
||||
const parentInstance = currentInstance as VaporComponentInstance
|
||||
const unmount = (parentNode?: ParentNode, transition?: TransitionHooks) => {
|
||||
if (transition) setTransitionHooks(vnode, transition)
|
||||
if (transition) setVNodeTransitionHooks(vnode, transition)
|
||||
internals.umt(vnode.component!, null, !!parentNode)
|
||||
}
|
||||
|
||||
|
@ -182,7 +195,7 @@ function createVDOMComponent(
|
|||
const prev = currentInstance
|
||||
simpleSetCurrentInstance(parentInstance)
|
||||
if (!isMounted) {
|
||||
if (transition) setTransitionHooks(vnode, transition)
|
||||
if (transition) setVNodeTransitionHooks(vnode, transition)
|
||||
internals.mt(
|
||||
vnode,
|
||||
parentNode,
|
||||
|
|
|
@ -50,6 +50,16 @@ interface PuppeteerUtils {
|
|||
clearValue(selector: string): Promise<any>
|
||||
timeout(time: number): Promise<any>
|
||||
nextFrame(): Promise<any>
|
||||
transitionStart(
|
||||
btnSelector: string,
|
||||
containerSelector: string,
|
||||
): Promise<{ classNames: string[]; innerHTML: string }>
|
||||
waitForElement(
|
||||
selector: string,
|
||||
text: string,
|
||||
classNames: string[],
|
||||
timeout?: number,
|
||||
): Promise<any>
|
||||
}
|
||||
|
||||
export function setupPuppeteer(args?: string[]): PuppeteerUtils {
|
||||
|
@ -200,6 +210,43 @@ export function setupPuppeteer(args?: string[]): PuppeteerUtils {
|
|||
})
|
||||
}
|
||||
|
||||
const transitionStart = (btnSelector: string, containerSelector: string) =>
|
||||
page.evaluate(
|
||||
([btnSel, containerSel]) => {
|
||||
;(document.querySelector(btnSel) as HTMLElement)!.click()
|
||||
return Promise.resolve().then(() => {
|
||||
const container = document.querySelector(containerSel)!
|
||||
return {
|
||||
classNames: container.className.split(/\s+/g),
|
||||
innerHTML: container.innerHTML,
|
||||
}
|
||||
})
|
||||
},
|
||||
[btnSelector, containerSelector],
|
||||
)
|
||||
|
||||
const waitForElement = (
|
||||
selector: string,
|
||||
text: string,
|
||||
classNames: string[], // if empty, check for no classes
|
||||
timeout = 2000,
|
||||
) =>
|
||||
page.waitForFunction(
|
||||
(sel, expectedText, expectedClasses) => {
|
||||
const el = document.querySelector(sel)
|
||||
const hasClasses =
|
||||
expectedClasses.length === 0
|
||||
? el?.classList.length === 0
|
||||
: expectedClasses.every(c => el?.classList.contains(c))
|
||||
const hasText = el?.textContent?.includes(expectedText)
|
||||
return !!el && hasClasses && hasText
|
||||
},
|
||||
{ timeout },
|
||||
selector,
|
||||
text,
|
||||
classNames,
|
||||
)
|
||||
|
||||
return {
|
||||
page: () => page,
|
||||
click,
|
||||
|
@ -219,5 +266,7 @@ export function setupPuppeteer(args?: string[]): PuppeteerUtils {
|
|||
clearValue,
|
||||
timeout,
|
||||
nextFrame,
|
||||
transitionStart,
|
||||
waitForElement,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue