2019-09-03 00:09:29 +08:00
|
|
|
import {
|
|
|
|
h,
|
2019-10-19 04:35:01 +08:00
|
|
|
withDirectives,
|
2019-09-03 00:09:29 +08:00
|
|
|
ref,
|
|
|
|
render,
|
|
|
|
nodeOps,
|
|
|
|
DirectiveHook,
|
|
|
|
VNode,
|
|
|
|
DirectiveBinding,
|
2022-04-12 15:54:03 +08:00
|
|
|
nextTick,
|
|
|
|
defineComponent
|
2019-09-03 00:09:29 +08:00
|
|
|
} from '@vue/runtime-test'
|
2020-03-17 00:47:49 +08:00
|
|
|
import { currentInstance, ComponentInternalInstance } from '../src/component'
|
2019-09-03 00:09:29 +08:00
|
|
|
|
2019-09-01 10:18:21 +08:00
|
|
|
describe('directives', () => {
|
2019-09-03 00:09:29 +08:00
|
|
|
it('should work', async () => {
|
|
|
|
const count = ref(0)
|
|
|
|
|
|
|
|
function assertBindings(binding: DirectiveBinding) {
|
|
|
|
expect(binding.value).toBe(count.value)
|
|
|
|
expect(binding.arg).toBe('foo')
|
2020-03-17 00:47:49 +08:00
|
|
|
expect(binding.instance).toBe(_instance && _instance.proxy)
|
2019-09-03 00:09:29 +08:00
|
|
|
expect(binding.modifiers && binding.modifiers.ok).toBe(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
const beforeMount = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should not be inserted yet
|
|
|
|
expect(el.parentNode).toBe(null)
|
|
|
|
expect(root.children.length).toBe(0)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const mounted = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should be inserted now
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const beforeUpdate = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
// node should not have been updated yet
|
|
|
|
expect(el.children[0].text).toBe(`${count.value - 1}`)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(_prevVnode)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const updated = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
// node should have been updated
|
|
|
|
expect(el.children[0].text).toBe(`${count.value}`)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(_prevVnode)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const beforeUnmount = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should be removed now
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const unmounted = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should have been removed
|
|
|
|
expect(el.parentNode).toBe(null)
|
|
|
|
expect(root.children.length).toBe(0)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
2020-02-11 02:15:36 +08:00
|
|
|
const dir = {
|
|
|
|
beforeMount,
|
|
|
|
mounted,
|
|
|
|
beforeUpdate,
|
|
|
|
updated,
|
|
|
|
beforeUnmount,
|
|
|
|
unmounted
|
|
|
|
}
|
|
|
|
|
2020-03-17 00:47:49 +08:00
|
|
|
let _instance: ComponentInternalInstance | null = null
|
2019-09-03 00:09:29 +08:00
|
|
|
let _vnode: VNode | null = null
|
|
|
|
let _prevVnode: VNode | null = null
|
|
|
|
const Comp = {
|
2020-03-17 00:47:49 +08:00
|
|
|
setup() {
|
|
|
|
_instance = currentInstance
|
|
|
|
},
|
2019-09-03 00:09:29 +08:00
|
|
|
render() {
|
|
|
|
_prevVnode = _vnode
|
2019-10-19 04:35:01 +08:00
|
|
|
_vnode = withDirectives(h('div', count.value), [
|
2019-09-04 06:11:04 +08:00
|
|
|
[
|
2020-02-11 02:15:36 +08:00
|
|
|
dir,
|
2019-09-04 06:11:04 +08:00
|
|
|
// value
|
|
|
|
count.value,
|
|
|
|
// argument
|
|
|
|
'foo',
|
|
|
|
// modifiers
|
|
|
|
{ ok: true }
|
|
|
|
]
|
2019-09-03 00:09:29 +08:00
|
|
|
])
|
|
|
|
return _vnode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(Comp), root)
|
|
|
|
|
2020-02-11 02:15:36 +08:00
|
|
|
expect(beforeMount).toHaveBeenCalledTimes(1)
|
|
|
|
expect(mounted).toHaveBeenCalledTimes(1)
|
2019-09-03 00:09:29 +08:00
|
|
|
|
|
|
|
count.value++
|
|
|
|
await nextTick()
|
2020-02-11 02:15:36 +08:00
|
|
|
expect(beforeUpdate).toHaveBeenCalledTimes(1)
|
|
|
|
expect(updated).toHaveBeenCalledTimes(1)
|
2019-09-03 00:09:29 +08:00
|
|
|
|
|
|
|
render(null, root)
|
2020-02-11 02:15:36 +08:00
|
|
|
expect(beforeUnmount).toHaveBeenCalledTimes(1)
|
|
|
|
expect(unmounted).toHaveBeenCalledTimes(1)
|
2019-09-03 00:09:29 +08:00
|
|
|
})
|
2019-10-16 14:12:26 +08:00
|
|
|
|
|
|
|
it('should work with a function directive', async () => {
|
|
|
|
const count = ref(0)
|
|
|
|
|
|
|
|
function assertBindings(binding: DirectiveBinding) {
|
|
|
|
expect(binding.value).toBe(count.value)
|
|
|
|
expect(binding.arg).toBe('foo')
|
2020-03-17 00:47:49 +08:00
|
|
|
expect(binding.instance).toBe(_instance && _instance.proxy)
|
2019-10-16 14:12:26 +08:00
|
|
|
expect(binding.modifiers && binding.modifiers.ok).toBe(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode).toBe(_vnode)
|
|
|
|
expect(prevVNode).toBe(_prevVnode)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
2020-03-17 00:47:49 +08:00
|
|
|
let _instance: ComponentInternalInstance | null = null
|
2019-10-16 14:12:26 +08:00
|
|
|
let _vnode: VNode | null = null
|
|
|
|
let _prevVnode: VNode | null = null
|
|
|
|
const Comp = {
|
2020-03-17 00:47:49 +08:00
|
|
|
setup() {
|
|
|
|
_instance = currentInstance
|
|
|
|
},
|
2019-10-16 14:12:26 +08:00
|
|
|
render() {
|
|
|
|
_prevVnode = _vnode
|
2019-10-19 04:35:01 +08:00
|
|
|
_vnode = withDirectives(h('div', count.value), [
|
2019-10-16 14:12:26 +08:00
|
|
|
[
|
|
|
|
fn,
|
|
|
|
// value
|
|
|
|
count.value,
|
|
|
|
// argument
|
|
|
|
'foo',
|
|
|
|
// modifiers
|
|
|
|
{ ok: true }
|
|
|
|
]
|
|
|
|
])
|
|
|
|
return _vnode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(Comp), root)
|
|
|
|
|
|
|
|
expect(fn).toHaveBeenCalledTimes(1)
|
|
|
|
|
|
|
|
count.value++
|
|
|
|
await nextTick()
|
|
|
|
expect(fn).toHaveBeenCalledTimes(2)
|
|
|
|
})
|
2020-02-11 02:15:36 +08:00
|
|
|
|
|
|
|
it('should work on component vnode', async () => {
|
|
|
|
const count = ref(0)
|
|
|
|
|
|
|
|
function assertBindings(binding: DirectiveBinding) {
|
|
|
|
expect(binding.value).toBe(count.value)
|
|
|
|
expect(binding.arg).toBe('foo')
|
2020-03-17 00:47:49 +08:00
|
|
|
expect(binding.instance).toBe(_instance && _instance.proxy)
|
2020-02-11 02:15:36 +08:00
|
|
|
expect(binding.modifiers && binding.modifiers.ok).toBe(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
const beforeMount = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should not be inserted yet
|
|
|
|
expect(el.parentNode).toBe(null)
|
|
|
|
expect(root.children.length).toBe(0)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const mounted = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should be inserted now
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const beforeUpdate = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
// node should not have been updated yet
|
|
|
|
// expect(el.children[0].text).toBe(`${count.value - 1}`)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode!.type).toBe(_prevVnode!.type)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const updated = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
// node should have been updated
|
|
|
|
expect(el.children[0].text).toBe(`${count.value}`)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode!.type).toBe(_prevVnode!.type)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const beforeUnmount = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should be removed now
|
|
|
|
expect(el.parentNode).toBe(root)
|
|
|
|
expect(root.children[0]).toBe(el)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const unmounted = jest.fn(((el, binding, vnode, prevVNode) => {
|
|
|
|
expect(el.tag).toBe('div')
|
|
|
|
// should have been removed
|
|
|
|
expect(el.parentNode).toBe(null)
|
|
|
|
expect(root.children.length).toBe(0)
|
|
|
|
|
|
|
|
assertBindings(binding)
|
|
|
|
|
|
|
|
expect(vnode.type).toBe(_vnode!.type)
|
|
|
|
expect(prevVNode).toBe(null)
|
|
|
|
}) as DirectiveHook)
|
|
|
|
|
|
|
|
const dir = {
|
|
|
|
beforeMount,
|
|
|
|
mounted,
|
|
|
|
beforeUpdate,
|
|
|
|
updated,
|
|
|
|
beforeUnmount,
|
|
|
|
unmounted
|
|
|
|
}
|
|
|
|
|
2020-03-17 00:47:49 +08:00
|
|
|
let _instance: ComponentInternalInstance | null = null
|
2020-02-11 02:15:36 +08:00
|
|
|
let _vnode: VNode | null = null
|
|
|
|
let _prevVnode: VNode | null = null
|
|
|
|
|
|
|
|
const Child = (props: { count: number }) => {
|
|
|
|
_prevVnode = _vnode
|
|
|
|
_vnode = h('div', props.count)
|
|
|
|
return _vnode
|
|
|
|
}
|
|
|
|
|
|
|
|
const Comp = {
|
2020-03-17 00:47:49 +08:00
|
|
|
setup() {
|
|
|
|
_instance = currentInstance
|
|
|
|
},
|
2020-02-11 02:15:36 +08:00
|
|
|
render() {
|
|
|
|
return withDirectives(h(Child, { count: count.value }), [
|
|
|
|
[
|
|
|
|
dir,
|
|
|
|
// value
|
|
|
|
count.value,
|
|
|
|
// argument
|
|
|
|
'foo',
|
|
|
|
// modifiers
|
|
|
|
{ ok: true }
|
|
|
|
]
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(Comp), root)
|
|
|
|
|
|
|
|
expect(beforeMount).toHaveBeenCalledTimes(1)
|
|
|
|
expect(mounted).toHaveBeenCalledTimes(1)
|
|
|
|
|
|
|
|
count.value++
|
|
|
|
await nextTick()
|
|
|
|
expect(beforeUpdate).toHaveBeenCalledTimes(1)
|
|
|
|
expect(updated).toHaveBeenCalledTimes(1)
|
|
|
|
|
|
|
|
render(null, root)
|
|
|
|
expect(beforeUnmount).toHaveBeenCalledTimes(1)
|
|
|
|
expect(unmounted).toHaveBeenCalledTimes(1)
|
|
|
|
})
|
2020-10-08 10:02:32 +08:00
|
|
|
|
|
|
|
// #2298
|
|
|
|
it('directive merging on component root', () => {
|
|
|
|
const d1 = {
|
|
|
|
mounted: jest.fn()
|
|
|
|
}
|
|
|
|
const d2 = {
|
|
|
|
mounted: jest.fn()
|
|
|
|
}
|
|
|
|
const Comp = {
|
|
|
|
render() {
|
|
|
|
return withDirectives(h('div'), [[d2]])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const App = {
|
|
|
|
name: 'App',
|
|
|
|
render() {
|
|
|
|
return h('div', [withDirectives(h(Comp), [[d1]])])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(App), root)
|
|
|
|
expect(d1.mounted).toHaveBeenCalled()
|
|
|
|
expect(d2.mounted).toHaveBeenCalled()
|
|
|
|
})
|
2021-05-28 04:53:19 +08:00
|
|
|
|
|
|
|
test('should disable tracking inside directive lifecycle hooks', async () => {
|
|
|
|
const count = ref(0)
|
|
|
|
const text = ref('')
|
|
|
|
const beforeUpdate = jest.fn(() => count.value++)
|
|
|
|
|
|
|
|
const App = {
|
|
|
|
render() {
|
|
|
|
return withDirectives(h('p', text.value), [
|
|
|
|
[
|
|
|
|
{
|
|
|
|
beforeUpdate
|
|
|
|
}
|
|
|
|
]
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(App), root)
|
|
|
|
expect(beforeUpdate).toHaveBeenCalledTimes(0)
|
|
|
|
expect(count.value).toBe(0)
|
|
|
|
|
|
|
|
text.value = 'foo'
|
|
|
|
await nextTick()
|
|
|
|
expect(beforeUpdate).toHaveBeenCalledTimes(1)
|
|
|
|
expect(count.value).toBe(1)
|
|
|
|
})
|
2022-04-12 15:54:03 +08:00
|
|
|
|
|
|
|
test('should receive exposeProxy for closed instances', async () => {
|
|
|
|
let res: string
|
|
|
|
const App = defineComponent({
|
|
|
|
setup(_, { expose }) {
|
|
|
|
expose({
|
|
|
|
msg: 'Test'
|
|
|
|
})
|
|
|
|
|
|
|
|
return () =>
|
|
|
|
withDirectives(h('p', 'Lore Ipsum'), [
|
|
|
|
[
|
|
|
|
{
|
|
|
|
mounted(el, { instance }) {
|
|
|
|
res = (instance as any).msg as string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
])
|
|
|
|
}
|
|
|
|
})
|
|
|
|
const root = nodeOps.createElement('div')
|
|
|
|
render(h(App), root)
|
|
|
|
expect(res!).toBe('Test')
|
|
|
|
})
|
2019-09-01 10:18:21 +08:00
|
|
|
})
|