mirror of https://github.com/vuejs/core.git
test: port tests
This commit is contained in:
parent
e8320b713b
commit
032f46f23c
|
@ -5,7 +5,9 @@ import {
|
|||
onDeactivated,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
reactive,
|
||||
ref,
|
||||
shallowRef,
|
||||
} from 'vue'
|
||||
import type { LooseRawProps, VaporComponent } from '../../src/component'
|
||||
import { makeRender } from '../_utils'
|
||||
|
@ -1037,4 +1039,151 @@ describe('VaporKeepAlive', () => {
|
|||
expect(html()).toBe(`<div>1</div><!--if-->`)
|
||||
})
|
||||
})
|
||||
|
||||
test.todo('should work with async component', async () => {})
|
||||
|
||||
test('handle error in async onActivated', async () => {
|
||||
const err = new Error('foo')
|
||||
const handler = vi.fn()
|
||||
const Child = defineVaporComponent({
|
||||
setup() {
|
||||
onActivated(async () => {
|
||||
throw err
|
||||
})
|
||||
|
||||
return template(`<span></span`)()
|
||||
},
|
||||
})
|
||||
|
||||
const { app } = define({
|
||||
setup() {
|
||||
return createComponent(VaporKeepAlive, null, {
|
||||
default: () => createComponent(Child),
|
||||
})
|
||||
},
|
||||
}).create()
|
||||
|
||||
app.config.errorHandler = handler
|
||||
app.mount(document.createElement('div'))
|
||||
|
||||
await nextTick()
|
||||
expect(handler).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('should avoid unmount later included components', async () => {
|
||||
const unmountedA = vi.fn()
|
||||
const mountedA = vi.fn()
|
||||
const activatedA = vi.fn()
|
||||
const deactivatedA = vi.fn()
|
||||
const unmountedB = vi.fn()
|
||||
const mountedB = vi.fn()
|
||||
|
||||
const A = defineVaporComponent({
|
||||
name: 'A',
|
||||
setup() {
|
||||
onMounted(mountedA)
|
||||
onUnmounted(unmountedA)
|
||||
onActivated(activatedA)
|
||||
onDeactivated(deactivatedA)
|
||||
return template(`<div>A</div>`)()
|
||||
},
|
||||
})
|
||||
|
||||
const B = defineVaporComponent({
|
||||
name: 'B',
|
||||
setup() {
|
||||
onMounted(mountedB)
|
||||
onUnmounted(unmountedB)
|
||||
return template(`<div>B</div>`)()
|
||||
},
|
||||
})
|
||||
|
||||
const include = reactive<string[]>([])
|
||||
const current = shallowRef(A)
|
||||
const { html } = define({
|
||||
setup() {
|
||||
return createComponent(
|
||||
VaporKeepAlive,
|
||||
{ include: () => include },
|
||||
{
|
||||
default: () => createDynamicComponent(() => current.value),
|
||||
},
|
||||
)
|
||||
},
|
||||
}).render()
|
||||
|
||||
expect(html()).toBe(`<div>A</div><!--dynamic-component-->`)
|
||||
expect(mountedA).toHaveBeenCalledTimes(1)
|
||||
expect(unmountedA).toHaveBeenCalledTimes(0)
|
||||
expect(activatedA).toHaveBeenCalledTimes(0)
|
||||
expect(deactivatedA).toHaveBeenCalledTimes(0)
|
||||
expect(mountedB).toHaveBeenCalledTimes(0)
|
||||
expect(unmountedB).toHaveBeenCalledTimes(0)
|
||||
|
||||
include.push('A') // cache A
|
||||
await nextTick()
|
||||
current.value = B // toggle to B
|
||||
await nextTick()
|
||||
expect(html()).toBe(`<div>B</div><!--dynamic-component-->`)
|
||||
expect(mountedA).toHaveBeenCalledTimes(1)
|
||||
expect(unmountedA).toHaveBeenCalledTimes(0)
|
||||
expect(activatedA).toHaveBeenCalledTimes(0)
|
||||
expect(deactivatedA).toHaveBeenCalledTimes(1)
|
||||
expect(mountedB).toHaveBeenCalledTimes(1)
|
||||
expect(unmountedB).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
test('remove component from include then switching child', async () => {
|
||||
const About = defineVaporComponent({
|
||||
name: 'About',
|
||||
setup() {
|
||||
return template(`<h1>About</h1>`)()
|
||||
},
|
||||
})
|
||||
const mountedHome = vi.fn()
|
||||
const unmountedHome = vi.fn()
|
||||
const activatedHome = vi.fn()
|
||||
const deactivatedHome = vi.fn()
|
||||
|
||||
const Home = defineVaporComponent({
|
||||
name: 'Home',
|
||||
setup() {
|
||||
onMounted(mountedHome)
|
||||
onUnmounted(unmountedHome)
|
||||
onDeactivated(deactivatedHome)
|
||||
onActivated(activatedHome)
|
||||
return template(`<h1>Home</h1>`)()
|
||||
},
|
||||
})
|
||||
|
||||
const activeViewName = ref('Home')
|
||||
const cacheList = reactive(['Home'])
|
||||
|
||||
define({
|
||||
setup() {
|
||||
return createComponent(
|
||||
VaporKeepAlive,
|
||||
{ include: () => cacheList },
|
||||
{
|
||||
default: () => {
|
||||
return createIf(
|
||||
() => activeViewName.value === 'Home',
|
||||
() => createComponent(Home),
|
||||
() => createComponent(About),
|
||||
)
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
}).render()
|
||||
|
||||
expect(mountedHome).toHaveBeenCalledTimes(1)
|
||||
expect(activatedHome).toHaveBeenCalledTimes(1)
|
||||
cacheList.splice(0, 1)
|
||||
await nextTick()
|
||||
activeViewName.value = 'About'
|
||||
await nextTick()
|
||||
expect(deactivatedHome).toHaveBeenCalledTimes(0)
|
||||
expect(unmountedHome).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -12,7 +12,13 @@ import {
|
|||
warn,
|
||||
watch,
|
||||
} from '@vue/runtime-dom'
|
||||
import { type Block, insert, isFragment, isValidBlock } from '../block'
|
||||
import {
|
||||
type Block,
|
||||
DynamicFragment,
|
||||
insert,
|
||||
isFragment,
|
||||
isValidBlock,
|
||||
} from '../block'
|
||||
import {
|
||||
type ObjectVaporComponent,
|
||||
type VaporComponent,
|
||||
|
@ -153,7 +159,7 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
|
|||
}
|
||||
}
|
||||
|
||||
const children = slots.default()
|
||||
let children = slots.default()
|
||||
if (isArray(children) && children.length > 1) {
|
||||
if (__DEV__) {
|
||||
warn(`KeepAlive should contain exactly one component child.`)
|
||||
|
@ -161,6 +167,13 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
|
|||
return children
|
||||
}
|
||||
|
||||
// wrap children in dynamic fragment
|
||||
if (!isFragment(children)) {
|
||||
const frag = new DynamicFragment()
|
||||
frag.update(() => children)
|
||||
children = frag
|
||||
}
|
||||
|
||||
function pruneCache(filter: (name: string) => boolean) {
|
||||
cache.forEach((instance, key) => {
|
||||
const name = getComponentName(instance.type)
|
||||
|
@ -197,16 +210,6 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
|
|||
},
|
||||
})
|
||||
|
||||
export const VaporKeepAlive = VaporKeepAliveImpl as any as {
|
||||
__isKeepAlive: true
|
||||
new (): {
|
||||
$props: KeepAliveProps
|
||||
$slots: {
|
||||
default(): Block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getInnerBlock(block: Block): VaporComponentInstance | undefined {
|
||||
if (isVaporComponent(block)) {
|
||||
return block
|
||||
|
|
|
@ -3,7 +3,7 @@ export { createVaporApp, createVaporSSRApp } from './apiCreateApp'
|
|||
export { defineVaporComponent } from './apiDefineComponent'
|
||||
export { vaporInteropPlugin } from './vdomInterop'
|
||||
export type { VaporDirective } from './directives/custom'
|
||||
export { VaporKeepAlive } from './components/KeepAlive'
|
||||
export { VaporKeepAliveImpl as VaporKeepAlive } from './components/KeepAlive'
|
||||
|
||||
// compiler-use only
|
||||
export { insert, prepend, remove, isFragment, VaporFragment } from './block'
|
||||
|
|
Loading…
Reference in New Issue