import connect from 'connect'
import sirv from 'sirv'
-describe('vdom / vapor interop', () => {
- const { page, click, text, enterValue } = setupPuppeteer()
-
- let server: any
- const port = '8193'
- beforeAll(() => {
- server = connect()
- .use(sirv(path.resolve(import.meta.dirname, '../dist')))
- .listen(port)
- process.on('SIGTERM', () => server && server.close())
- })
+const { page, click, html, value, text, enterValue } = setupPuppeteer()
+
+let server: any
+const port = '8193'
+beforeAll(() => {
+ server = connect()
+ .use(sirv(path.resolve(import.meta.dirname, '../dist')))
+ .listen(port)
+ process.on('SIGTERM', () => server && server.close())
+})
- afterAll(() => {
- server.close()
- })
+afterAll(() => {
+ server.close()
+})
+beforeEach(async () => {
+ const baseUrl = `http://localhost:${port}/interop/`
+ await page().goto(baseUrl)
+ await page().waitForSelector('#app')
+})
+
+describe('vdom / vapor interop', () => {
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')
},
E2E_TIMEOUT,
)
+
+ describe('keepalive', () => {
+ test(
+ 'render vapor component',
+ async () => {
+ const testSelector = '.render-vapor-component'
+ const btnShow = `${testSelector} .btn-show`
+ const btnToggle = `${testSelector} .btn-toggle`
+ const container = `${testSelector} > div`
+ const inputSelector = `${testSelector} input`
+
+ let calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toStrictEqual(['mounted', 'activated'])
+
+ expect(await html(container)).toBe('<input type="text">')
+ expect(await value(inputSelector)).toBe('vapor')
+
+ // change input value
+ await enterValue(inputSelector, 'changed')
+ expect(await value(inputSelector)).toBe('changed')
+
+ // deactivate
+ await click(btnToggle)
+ expect(await html(container)).toBe('<!---->')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toStrictEqual(['deactivated'])
+
+ // activate
+ await click(btnToggle)
+ expect(await html(container)).toBe('<input type="text">')
+ expect(await value(inputSelector)).toBe('changed')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toStrictEqual(['activated'])
+
+ // unmount keepalive
+ await click(btnShow)
+ expect(await html(container)).toBe('<!---->')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toStrictEqual(['deactivated', 'unmounted'])
+
+ // mount keepalive
+ await click(btnShow)
+ expect(await html(container)).toBe('<input type="text">')
+ expect(await value(inputSelector)).toBe('vapor')
+ calls = await page().evaluate(() => {
+ return (window as any).getCalls()
+ })
+ expect(calls).toStrictEqual(['mounted', 'activated'])
+ },
+ E2E_TIMEOUT,
+ )
+ })
})
<script setup lang="ts">
import { ref } from 'vue'
import VaporComp from './VaporComp.vue'
+import SimpleVaporComp from './components/SimpleVaporComp.vue'
const msg = ref('hello')
-const passSlot = ref(true)
+const passSlot = ref(true);
+
+(window as any).calls = [];
+(window as any).getCalls = () => {
+ const ret = (window as any).calls.slice();
+ (window as any).calls = []
+ return ret
+}
+
+const show = ref(true)
+const toggle = ref(true)
</script>
<template>
<template #test v-if="passSlot">A test slot</template>
</VaporComp>
+
+ <!-- keepalive -->
+ <div class="render-vapor-component">
+ <button class="btn-show" @click="show = !show">show</button>
+ <button class="btn-toggle" @click="toggle = !toggle">toggle</button>
+ <div>
+ <KeepAlive v-if="show">
+ <SimpleVaporComp v-if="toggle" />
+ </KeepAlive>
+ </div>
+ </div>
+ <!-- keepalive end -->
</template>
unmountComponent,
} from './component'
import { type Block, VaporFragment, insert, remove } from './block'
-import { EMPTY_OBJ, ShapeFlags, extend, isFunction } from '@vue/shared'
+import {
+ EMPTY_OBJ,
+ ShapeFlags,
+ extend,
+ isFunction,
+ isReservedProp,
+} from '@vue/shared'
import { type RawProps, rawPropsProxyHandlers } from './componentProps'
import type { RawSlots, VaporSlot } from './componentSlots'
import { renderEffect } from './renderEffect'
const prev = currentInstance
simpleSetCurrentInstance(parentComponent)
- const propsRef = shallowRef(vnode.props)
+ // filter out reserved props
+ const props: VNode['props'] = {}
+ for (const key in vnode.props) {
+ if (!isReservedProp(key)) {
+ props[key] = vnode.props[key]
+ }
+ }
+
+ const propsRef = shallowRef(props)
const slotsRef = shallowRef(vnode.children)
// @ts-expect-error