Skip to content

Commit 811f28a

Browse files
committed
test(runtime-core): tests for vnode hooks
1 parent ebc1ca8 commit 811f28a

File tree

2 files changed

+124
-21
lines changed

2 files changed

+124
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import {
2+
h,
3+
render,
4+
nodeOps,
5+
VNodeProps,
6+
TestElement,
7+
NodeTypes,
8+
VNode
9+
} from '@vue/runtime-test'
10+
11+
describe('renderer: vnode hooks', () => {
12+
function assertHooks(hooks: VNodeProps, vnode1: VNode, vnode2: VNode) {
13+
const root = nodeOps.createElement('div')
14+
render(vnode1, root)
15+
expect(hooks.onVnodeBeforeMount).toHaveBeenCalledWith(vnode1, null)
16+
expect(hooks.onVnodeMounted).toHaveBeenCalledWith(vnode1, null)
17+
expect(hooks.onVnodeBeforeUpdate).not.toHaveBeenCalled()
18+
expect(hooks.onVnodeUpdated).not.toHaveBeenCalled()
19+
expect(hooks.onVnodeBeforeUnmount).not.toHaveBeenCalled()
20+
expect(hooks.onVnodeUnmounted).not.toHaveBeenCalled()
21+
22+
// update
23+
render(vnode2, root)
24+
expect(hooks.onVnodeBeforeMount).toHaveBeenCalledTimes(1)
25+
expect(hooks.onVnodeMounted).toHaveBeenCalledTimes(1)
26+
expect(hooks.onVnodeBeforeUpdate).toHaveBeenCalledWith(vnode2, vnode1)
27+
expect(hooks.onVnodeUpdated).toHaveBeenCalledWith(vnode2, vnode1)
28+
expect(hooks.onVnodeBeforeUnmount).not.toHaveBeenCalled()
29+
expect(hooks.onVnodeUnmounted).not.toHaveBeenCalled()
30+
31+
// unmount
32+
render(null, root)
33+
expect(hooks.onVnodeBeforeMount).toHaveBeenCalledTimes(1)
34+
expect(hooks.onVnodeMounted).toHaveBeenCalledTimes(1)
35+
expect(hooks.onVnodeBeforeUpdate).toHaveBeenCalledTimes(1)
36+
expect(hooks.onVnodeUpdated).toHaveBeenCalledTimes(1)
37+
expect(hooks.onVnodeBeforeUnmount).toHaveBeenCalledWith(vnode2, null)
38+
expect(hooks.onVnodeUnmounted).toHaveBeenCalledWith(vnode2, null)
39+
}
40+
41+
test('should work on element', () => {
42+
const hooks: VNodeProps = {
43+
onVnodeBeforeMount: jest.fn(),
44+
onVnodeMounted: jest.fn(),
45+
onVnodeBeforeUpdate: jest.fn(vnode => {
46+
expect((vnode.el as TestElement).children[0]).toMatchObject({
47+
type: NodeTypes.TEXT,
48+
text: 'foo'
49+
})
50+
}),
51+
onVnodeUpdated: jest.fn(vnode => {
52+
expect((vnode.el as TestElement).children[0]).toMatchObject({
53+
type: NodeTypes.TEXT,
54+
text: 'bar'
55+
})
56+
}),
57+
onVnodeBeforeUnmount: jest.fn(),
58+
onVnodeUnmounted: jest.fn()
59+
}
60+
61+
assertHooks(hooks, h('div', hooks, 'foo'), h('div', hooks, 'bar'))
62+
})
63+
64+
test('should work on component', () => {
65+
const Comp = (props: { msg: string }) => props.msg
66+
67+
const hooks: VNodeProps = {
68+
onVnodeBeforeMount: jest.fn(),
69+
onVnodeMounted: jest.fn(),
70+
onVnodeBeforeUpdate: jest.fn(vnode => {
71+
expect(vnode.el as TestElement).toMatchObject({
72+
type: NodeTypes.TEXT,
73+
text: 'foo'
74+
})
75+
}),
76+
onVnodeUpdated: jest.fn(vnode => {
77+
expect(vnode.el as TestElement).toMatchObject({
78+
type: NodeTypes.TEXT,
79+
text: 'bar'
80+
})
81+
}),
82+
onVnodeBeforeUnmount: jest.fn(),
83+
onVnodeUnmounted: jest.fn()
84+
}
85+
86+
assertHooks(
87+
hooks,
88+
h(Comp, {
89+
...hooks,
90+
msg: 'foo'
91+
}),
92+
h(Comp, {
93+
...hooks,
94+
msg: 'bar'
95+
})
96+
)
97+
})
98+
})

packages/runtime-core/src/renderer.ts

+26-21
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,7 @@ function baseCreateRenderer<
11521152
const nextTree = renderComponentRoot(instance)
11531153
const prevTree = instance.subTree
11541154
instance.subTree = nextTree
1155+
next.el = vnode.el
11551156
// beforeUpdate hook
11561157
if (bu !== null) {
11571158
invokeHooks(bu)
@@ -1673,36 +1674,40 @@ function baseCreateRenderer<
16731674
setRef(ref, null, parentComponent, null)
16741675
}
16751676

1677+
if ((vnodeHook = props && props.onVnodeBeforeUnmount) != null) {
1678+
invokeVNodeHook(vnodeHook, parentComponent, vnode)
1679+
}
1680+
16761681
if (shapeFlag & ShapeFlags.COMPONENT) {
16771682
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
16781683
;(parentComponent!.sink as KeepAliveSink).deactivate(vnode)
16791684
} else {
16801685
unmountComponent(vnode.component!, parentSuspense, doRemove)
16811686
}
1682-
return
1683-
}
1684-
1685-
if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
1686-
vnode.suspense!.unmount(parentSuspense, doRemove)
1687-
return
1688-
}
1687+
} else {
1688+
if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
1689+
vnode.suspense!.unmount(parentSuspense, doRemove)
1690+
return
1691+
}
16891692

1690-
if ((vnodeHook = props && props.onVnodeBeforeUnmount) != null) {
1691-
invokeVNodeHook(vnodeHook, parentComponent, vnode)
1692-
}
1693-
if (shouldInvokeDirs) {
1694-
invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')
1695-
}
1693+
if (shouldInvokeDirs) {
1694+
invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')
1695+
}
16961696

1697-
if (dynamicChildren != null) {
1698-
// fast path for block nodes: only need to unmount dynamic children.
1699-
unmountChildren(dynamicChildren, parentComponent, parentSuspense)
1700-
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
1701-
unmountChildren(children as HostVNode[], parentComponent, parentSuspense)
1702-
}
1697+
if (dynamicChildren != null) {
1698+
// fast path for block nodes: only need to unmount dynamic children.
1699+
unmountChildren(dynamicChildren, parentComponent, parentSuspense)
1700+
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
1701+
unmountChildren(
1702+
children as HostVNode[],
1703+
parentComponent,
1704+
parentSuspense
1705+
)
1706+
}
17031707

1704-
if (doRemove) {
1705-
remove(vnode)
1708+
if (doRemove) {
1709+
remove(vnode)
1710+
}
17061711
}
17071712

17081713
if (

0 commit comments

Comments
 (0)