Skip to content

Commit 35475c0

Browse files
authored
feat(vapor): vapor keepalive (#13186)
1 parent 7870fc0 commit 35475c0

File tree

24 files changed

+2030
-114
lines changed

24 files changed

+2030
-114
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import path from 'node:path'
2+
import {
3+
E2E_TIMEOUT,
4+
setupPuppeteer,
5+
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
6+
import connect from 'connect'
7+
import sirv from 'sirv'
8+
const { page, html, click, value, enterValue } = setupPuppeteer()
9+
10+
describe('vapor keepalive', () => {
11+
let server: any
12+
const port = '8197'
13+
beforeAll(() => {
14+
server = connect()
15+
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
16+
.listen(port)
17+
process.on('SIGTERM', () => server && server.close())
18+
})
19+
20+
beforeEach(async () => {
21+
const baseUrl = `http://localhost:${port}/keepalive/`
22+
await page().goto(baseUrl)
23+
await page().waitForSelector('#app')
24+
})
25+
26+
afterAll(() => {
27+
server.close()
28+
})
29+
30+
test(
31+
'render vdom component',
32+
async () => {
33+
const testSelector = '.render-vdom-component'
34+
const btnShow = `${testSelector} .btn-show`
35+
const btnToggle = `${testSelector} .btn-toggle`
36+
const container = `${testSelector} > div`
37+
const inputSelector = `${testSelector} input`
38+
39+
let calls = await page().evaluate(() => {
40+
return (window as any).getCalls()
41+
})
42+
expect(calls).toStrictEqual(['mounted', 'activated'])
43+
44+
expect(await html(container)).toBe('<input type="text">')
45+
expect(await value(inputSelector)).toBe('vdom')
46+
47+
// change input value
48+
await enterValue(inputSelector, 'changed')
49+
expect(await value(inputSelector)).toBe('changed')
50+
51+
// deactivate
52+
await click(btnToggle)
53+
expect(await html(container)).toBe('')
54+
calls = await page().evaluate(() => {
55+
return (window as any).getCalls()
56+
})
57+
expect(calls).toStrictEqual(['deactivated'])
58+
59+
// activate
60+
await click(btnToggle)
61+
expect(await html(container)).toBe('<input type="text">')
62+
expect(await value(inputSelector)).toBe('changed')
63+
calls = await page().evaluate(() => {
64+
return (window as any).getCalls()
65+
})
66+
expect(calls).toStrictEqual(['activated'])
67+
68+
// unmount keepalive
69+
await click(btnShow)
70+
expect(await html(container)).toBe('')
71+
calls = await page().evaluate(() => {
72+
return (window as any).getCalls()
73+
})
74+
expect(calls).toStrictEqual(['deactivated', 'unmounted'])
75+
76+
// mount keepalive
77+
await click(btnShow)
78+
expect(await html(container)).toBe('<input type="text">')
79+
expect(await value(inputSelector)).toBe('vdom')
80+
calls = await page().evaluate(() => {
81+
return (window as any).getCalls()
82+
})
83+
expect(calls).toStrictEqual(['mounted', 'activated'])
84+
},
85+
E2E_TIMEOUT,
86+
)
87+
})

packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,36 @@ const {
1111
text,
1212
enterValue,
1313
html,
14+
value,
1415
transitionStart,
1516
waitForElement,
1617
nextFrame,
1718
timeout,
1819
} = setupPuppeteer()
1920

21+
let server: any
22+
const port = '8193'
23+
beforeAll(() => {
24+
server = connect()
25+
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
26+
.listen(port)
27+
process.on('SIGTERM', () => server && server.close())
28+
})
29+
afterAll(() => {
30+
server.close()
31+
})
32+
33+
beforeEach(async () => {
34+
const baseUrl = `http://localhost:${port}/interop/`
35+
await page().goto(baseUrl)
36+
await page().waitForSelector('#app')
37+
})
38+
2039
const duration = process.env.CI ? 200 : 50
2140
const buffer = process.env.CI ? 50 : 20
2241
const transitionFinish = (time = duration) => timeout(time + buffer)
2342

2443
describe('vdom / vapor interop', () => {
25-
let server: any
26-
const port = '8193'
27-
beforeAll(() => {
28-
server = connect()
29-
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
30-
.listen(port)
31-
process.on('SIGTERM', () => server && server.close())
32-
})
33-
34-
afterAll(() => {
35-
server.close()
36-
})
37-
3844
beforeEach(async () => {
3945
const baseUrl = `http://localhost:${port}/interop/`
4046
await page().goto(baseUrl)
@@ -98,6 +104,66 @@ describe('vdom / vapor interop', () => {
98104
E2E_TIMEOUT,
99105
)
100106

107+
describe('keepalive', () => {
108+
test(
109+
'render vapor component',
110+
async () => {
111+
const testSelector = '.render-vapor-component'
112+
const btnShow = `${testSelector} .btn-show`
113+
const btnToggle = `${testSelector} .btn-toggle`
114+
const container = `${testSelector} > div`
115+
const inputSelector = `${testSelector} input`
116+
117+
let calls = await page().evaluate(() => {
118+
return (window as any).getCalls()
119+
})
120+
expect(calls).toStrictEqual(['mounted', 'activated'])
121+
122+
expect(await html(container)).toBe('<input type="text">')
123+
expect(await value(inputSelector)).toBe('vapor')
124+
125+
// change input value
126+
await enterValue(inputSelector, 'changed')
127+
expect(await value(inputSelector)).toBe('changed')
128+
129+
// deactivate
130+
await click(btnToggle)
131+
expect(await html(container)).toBe('<!---->')
132+
calls = await page().evaluate(() => {
133+
return (window as any).getCalls()
134+
})
135+
expect(calls).toStrictEqual(['deactivated'])
136+
137+
// activate
138+
await click(btnToggle)
139+
expect(await html(container)).toBe('<input type="text">')
140+
expect(await value(inputSelector)).toBe('changed')
141+
calls = await page().evaluate(() => {
142+
return (window as any).getCalls()
143+
})
144+
expect(calls).toStrictEqual(['activated'])
145+
146+
// unmount keepalive
147+
await click(btnShow)
148+
expect(await html(container)).toBe('<!---->')
149+
calls = await page().evaluate(() => {
150+
return (window as any).getCalls()
151+
})
152+
expect(calls).toStrictEqual(['deactivated', 'unmounted'])
153+
154+
// mount keepalive
155+
await click(btnShow)
156+
expect(await html(container)).toBe('<input type="text">')
157+
expect(await value(inputSelector)).toBe('vapor')
158+
calls = await page().evaluate(() => {
159+
return (window as any).getCalls()
160+
})
161+
expect(calls).toStrictEqual(['mounted', 'activated'])
162+
},
163+
E2E_TIMEOUT,
164+
)
165+
})
166+
101167
describe('vdom transition', () => {
102168
test(
103169
'render vapor component',

packages-private/vapor-e2e-test/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<a href="/interop/">VDOM / Vapor interop</a>
22
<a href="/todomvc/">Vapor TodoMVC</a>
3+
<a href="/keepalive/">Vapor KeepAlive</a>
34
<a href="/transition/">Vapor Transition</a>
45
<a href="/transition-group/">Vapor TransitionGroup</a>
56

packages-private/vapor-e2e-test/interop/App.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
<script setup lang="ts">
22
import { ref, shallowRef } from 'vue'
33
import VaporComp from './VaporComp.vue'
4+
import SimpleVaporComp from './components/SimpleVaporComp.vue'
45
import VaporCompA from '../transition/components/VaporCompA.vue'
56
import VdomComp from '../transition/components/VdomComp.vue'
67
import VaporSlot from '../transition/components/VaporSlot.vue'
78
89
const msg = ref('hello')
910
const passSlot = ref(true)
1011
12+
;(window as any).calls = []
13+
;(window as any).getCalls = () => {
14+
const ret = (window as any).calls.slice()
15+
;(window as any).calls = []
16+
return ret
17+
}
18+
19+
const show = ref(true)
20+
const toggle = ref(true)
1121
const toggleVapor = ref(true)
1222
const interopComponent = shallowRef(VdomComp)
1323
function toggleInteropComponent() {
@@ -33,6 +43,17 @@ const enterClick = () => items.value.push('d', 'e')
3343
<template #test v-if="passSlot">A test slot</template>
3444
</VaporComp>
3545

46+
<!-- keepalive -->
47+
<div class="render-vapor-component">
48+
<button class="btn-show" @click="show = !show">show</button>
49+
<button class="btn-toggle" @click="toggle = !toggle">toggle</button>
50+
<div>
51+
<KeepAlive v-if="show">
52+
<SimpleVaporComp v-if="toggle" />
53+
</KeepAlive>
54+
</div>
55+
</div>
56+
<!-- keepalive end -->
3657
<!-- transition interop -->
3758
<div>
3859
<div class="trans-vapor">
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script vapor>
2+
import { onActivated, onDeactivated, onMounted, onUnmounted, ref } from 'vue'
3+
const msg = ref('vapor')
4+
5+
onMounted(() => {
6+
window.calls.push('mounted')
7+
})
8+
onActivated(() => {
9+
window.calls.push('activated')
10+
})
11+
onDeactivated(() => {
12+
window.calls.push('deactivated')
13+
})
14+
onUnmounted(() => {
15+
window.calls.push('unmounted')
16+
})
17+
</script>
18+
<template>
19+
<input type="text" v-model="msg" />
20+
</template>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<script vapor>
2+
import { ref } from 'vue'
3+
import VdomComp from './components/VdomComp.vue'
4+
5+
window.calls = []
6+
window.getCalls = () => {
7+
const ret = window.calls.slice()
8+
window.calls = []
9+
return ret
10+
}
11+
12+
const show = ref(true)
13+
const toggle = ref(true)
14+
</script>
15+
16+
<template>
17+
<div class="render-vdom-component">
18+
<button class="btn-show" @click="show = !show">show</button>
19+
<button class="btn-toggle" @click="toggle = !toggle">toggle</button>
20+
<div>
21+
<KeepAlive v-if="show">
22+
<VdomComp v-if="toggle"></VdomComp>
23+
</KeepAlive>
24+
</div>
25+
</div>
26+
</template>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script setup>
2+
import { onActivated, onDeactivated, onMounted, onUnmounted, ref } from 'vue'
3+
const msg = ref('vdom')
4+
5+
onMounted(() => {
6+
window.calls.push('mounted')
7+
})
8+
onActivated(() => {
9+
window.calls.push('activated')
10+
})
11+
onDeactivated(() => {
12+
window.calls.push('deactivated')
13+
})
14+
onUnmounted(() => {
15+
window.calls.push('unmounted')
16+
})
17+
</script>
18+
<template>
19+
<input type="text" v-model="msg" />
20+
</template>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<script type="module" src="./main.ts"></script>
2+
<div id="app"></div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { createVaporApp, vaporInteropPlugin } from 'vue'
2+
import App from './App.vue'
3+
4+
createVaporApp(App).use(vaporInteropPlugin).mount('#app')

packages-private/vapor-e2e-test/vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default defineConfig({
1414
input: {
1515
interop: resolve(import.meta.dirname, 'interop/index.html'),
1616
todomvc: resolve(import.meta.dirname, 'todomvc/index.html'),
17+
keepalive: resolve(import.meta.dirname, 'keepalive/index.html'),
1718
transition: resolve(import.meta.dirname, 'transition/index.html'),
1819
transitionGroup: resolve(
1920
import.meta.dirname,

0 commit comments

Comments
 (0)