2
0

directives.spec.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. import {
  2. h,
  3. withDirectives,
  4. ref,
  5. render,
  6. nodeOps,
  7. DirectiveHook,
  8. VNode,
  9. DirectiveBinding,
  10. nextTick
  11. } from '@vue/runtime-test'
  12. import { currentInstance, ComponentInternalInstance } from '../src/component'
  13. describe('directives', () => {
  14. it('should work', async () => {
  15. const count = ref(0)
  16. function assertBindings(binding: DirectiveBinding) {
  17. expect(binding.value).toBe(count.value)
  18. expect(binding.arg).toBe('foo')
  19. expect(binding.instance).toBe(_instance && _instance.proxy)
  20. expect(binding.modifiers && binding.modifiers.ok).toBe(true)
  21. }
  22. const beforeMount = jest.fn(((el, binding, vnode, prevVNode) => {
  23. expect(el.tag).toBe('div')
  24. // should not be inserted yet
  25. expect(el.parentNode).toBe(null)
  26. expect(root.children.length).toBe(0)
  27. assertBindings(binding)
  28. expect(vnode).toBe(_vnode)
  29. expect(prevVNode).toBe(null)
  30. }) as DirectiveHook)
  31. const mounted = jest.fn(((el, binding, vnode, prevVNode) => {
  32. expect(el.tag).toBe('div')
  33. // should be inserted now
  34. expect(el.parentNode).toBe(root)
  35. expect(root.children[0]).toBe(el)
  36. assertBindings(binding)
  37. expect(vnode).toBe(_vnode)
  38. expect(prevVNode).toBe(null)
  39. }) as DirectiveHook)
  40. const beforeUpdate = jest.fn(((el, binding, vnode, prevVNode) => {
  41. expect(el.tag).toBe('div')
  42. expect(el.parentNode).toBe(root)
  43. expect(root.children[0]).toBe(el)
  44. // node should not have been updated yet
  45. expect(el.children[0].text).toBe(`${count.value - 1}`)
  46. assertBindings(binding)
  47. expect(vnode).toBe(_vnode)
  48. expect(prevVNode).toBe(_prevVnode)
  49. }) as DirectiveHook)
  50. const updated = jest.fn(((el, binding, vnode, prevVNode) => {
  51. expect(el.tag).toBe('div')
  52. expect(el.parentNode).toBe(root)
  53. expect(root.children[0]).toBe(el)
  54. // node should have been updated
  55. expect(el.children[0].text).toBe(`${count.value}`)
  56. assertBindings(binding)
  57. expect(vnode).toBe(_vnode)
  58. expect(prevVNode).toBe(_prevVnode)
  59. }) as DirectiveHook)
  60. const beforeUnmount = jest.fn(((el, binding, vnode, prevVNode) => {
  61. expect(el.tag).toBe('div')
  62. // should be removed now
  63. expect(el.parentNode).toBe(root)
  64. expect(root.children[0]).toBe(el)
  65. assertBindings(binding)
  66. expect(vnode).toBe(_vnode)
  67. expect(prevVNode).toBe(null)
  68. }) as DirectiveHook)
  69. const unmounted = jest.fn(((el, binding, vnode, prevVNode) => {
  70. expect(el.tag).toBe('div')
  71. // should have been removed
  72. expect(el.parentNode).toBe(null)
  73. expect(root.children.length).toBe(0)
  74. assertBindings(binding)
  75. expect(vnode).toBe(_vnode)
  76. expect(prevVNode).toBe(null)
  77. }) as DirectiveHook)
  78. const dir = {
  79. beforeMount,
  80. mounted,
  81. beforeUpdate,
  82. updated,
  83. beforeUnmount,
  84. unmounted
  85. }
  86. let _instance: ComponentInternalInstance | null = null
  87. let _vnode: VNode | null = null
  88. let _prevVnode: VNode | null = null
  89. const Comp = {
  90. setup() {
  91. _instance = currentInstance
  92. },
  93. render() {
  94. _prevVnode = _vnode
  95. _vnode = withDirectives(h('div', count.value), [
  96. [
  97. dir,
  98. // value
  99. count.value,
  100. // argument
  101. 'foo',
  102. // modifiers
  103. { ok: true }
  104. ]
  105. ])
  106. return _vnode
  107. }
  108. }
  109. const root = nodeOps.createElement('div')
  110. render(h(Comp), root)
  111. expect(beforeMount).toHaveBeenCalledTimes(1)
  112. expect(mounted).toHaveBeenCalledTimes(1)
  113. count.value++
  114. await nextTick()
  115. expect(beforeUpdate).toHaveBeenCalledTimes(1)
  116. expect(updated).toHaveBeenCalledTimes(1)
  117. render(null, root)
  118. expect(beforeUnmount).toHaveBeenCalledTimes(1)
  119. expect(unmounted).toHaveBeenCalledTimes(1)
  120. })
  121. it('should work with a function directive', async () => {
  122. const count = ref(0)
  123. function assertBindings(binding: DirectiveBinding) {
  124. expect(binding.value).toBe(count.value)
  125. expect(binding.arg).toBe('foo')
  126. expect(binding.instance).toBe(_instance && _instance.proxy)
  127. expect(binding.modifiers && binding.modifiers.ok).toBe(true)
  128. }
  129. const fn = jest.fn(((el, binding, vnode, prevVNode) => {
  130. expect(el.tag).toBe('div')
  131. expect(el.parentNode).toBe(root)
  132. assertBindings(binding)
  133. expect(vnode).toBe(_vnode)
  134. expect(prevVNode).toBe(_prevVnode)
  135. }) as DirectiveHook)
  136. let _instance: ComponentInternalInstance | null = null
  137. let _vnode: VNode | null = null
  138. let _prevVnode: VNode | null = null
  139. const Comp = {
  140. setup() {
  141. _instance = currentInstance
  142. },
  143. render() {
  144. _prevVnode = _vnode
  145. _vnode = withDirectives(h('div', count.value), [
  146. [
  147. fn,
  148. // value
  149. count.value,
  150. // argument
  151. 'foo',
  152. // modifiers
  153. { ok: true }
  154. ]
  155. ])
  156. return _vnode
  157. }
  158. }
  159. const root = nodeOps.createElement('div')
  160. render(h(Comp), root)
  161. expect(fn).toHaveBeenCalledTimes(1)
  162. count.value++
  163. await nextTick()
  164. expect(fn).toHaveBeenCalledTimes(2)
  165. })
  166. it('should work on component vnode', async () => {
  167. const count = ref(0)
  168. function assertBindings(binding: DirectiveBinding) {
  169. expect(binding.value).toBe(count.value)
  170. expect(binding.arg).toBe('foo')
  171. expect(binding.instance).toBe(_instance && _instance.proxy)
  172. expect(binding.modifiers && binding.modifiers.ok).toBe(true)
  173. }
  174. const beforeMount = jest.fn(((el, binding, vnode, prevVNode) => {
  175. expect(el.tag).toBe('div')
  176. // should not be inserted yet
  177. expect(el.parentNode).toBe(null)
  178. expect(root.children.length).toBe(0)
  179. assertBindings(binding)
  180. expect(vnode.type).toBe(_vnode!.type)
  181. expect(prevVNode).toBe(null)
  182. }) as DirectiveHook)
  183. const mounted = jest.fn(((el, binding, vnode, prevVNode) => {
  184. expect(el.tag).toBe('div')
  185. // should be inserted now
  186. expect(el.parentNode).toBe(root)
  187. expect(root.children[0]).toBe(el)
  188. assertBindings(binding)
  189. expect(vnode.type).toBe(_vnode!.type)
  190. expect(prevVNode).toBe(null)
  191. }) as DirectiveHook)
  192. const beforeUpdate = jest.fn(((el, binding, vnode, prevVNode) => {
  193. expect(el.tag).toBe('div')
  194. expect(el.parentNode).toBe(root)
  195. expect(root.children[0]).toBe(el)
  196. // node should not have been updated yet
  197. // expect(el.children[0].text).toBe(`${count.value - 1}`)
  198. assertBindings(binding)
  199. expect(vnode.type).toBe(_vnode!.type)
  200. expect(prevVNode!.type).toBe(_prevVnode!.type)
  201. }) as DirectiveHook)
  202. const updated = jest.fn(((el, binding, vnode, prevVNode) => {
  203. expect(el.tag).toBe('div')
  204. expect(el.parentNode).toBe(root)
  205. expect(root.children[0]).toBe(el)
  206. // node should have been updated
  207. expect(el.children[0].text).toBe(`${count.value}`)
  208. assertBindings(binding)
  209. expect(vnode.type).toBe(_vnode!.type)
  210. expect(prevVNode!.type).toBe(_prevVnode!.type)
  211. }) as DirectiveHook)
  212. const beforeUnmount = jest.fn(((el, binding, vnode, prevVNode) => {
  213. expect(el.tag).toBe('div')
  214. // should be removed now
  215. expect(el.parentNode).toBe(root)
  216. expect(root.children[0]).toBe(el)
  217. assertBindings(binding)
  218. expect(vnode.type).toBe(_vnode!.type)
  219. expect(prevVNode).toBe(null)
  220. }) as DirectiveHook)
  221. const unmounted = jest.fn(((el, binding, vnode, prevVNode) => {
  222. expect(el.tag).toBe('div')
  223. // should have been removed
  224. expect(el.parentNode).toBe(null)
  225. expect(root.children.length).toBe(0)
  226. assertBindings(binding)
  227. expect(vnode.type).toBe(_vnode!.type)
  228. expect(prevVNode).toBe(null)
  229. }) as DirectiveHook)
  230. const dir = {
  231. beforeMount,
  232. mounted,
  233. beforeUpdate,
  234. updated,
  235. beforeUnmount,
  236. unmounted
  237. }
  238. let _instance: ComponentInternalInstance | null = null
  239. let _vnode: VNode | null = null
  240. let _prevVnode: VNode | null = null
  241. const Child = (props: { count: number }) => {
  242. _prevVnode = _vnode
  243. _vnode = h('div', props.count)
  244. return _vnode
  245. }
  246. const Comp = {
  247. setup() {
  248. _instance = currentInstance
  249. },
  250. render() {
  251. return withDirectives(h(Child, { count: count.value }), [
  252. [
  253. dir,
  254. // value
  255. count.value,
  256. // argument
  257. 'foo',
  258. // modifiers
  259. { ok: true }
  260. ]
  261. ])
  262. }
  263. }
  264. const root = nodeOps.createElement('div')
  265. render(h(Comp), root)
  266. expect(beforeMount).toHaveBeenCalledTimes(1)
  267. expect(mounted).toHaveBeenCalledTimes(1)
  268. count.value++
  269. await nextTick()
  270. expect(beforeUpdate).toHaveBeenCalledTimes(1)
  271. expect(updated).toHaveBeenCalledTimes(1)
  272. render(null, root)
  273. expect(beforeUnmount).toHaveBeenCalledTimes(1)
  274. expect(unmounted).toHaveBeenCalledTimes(1)
  275. })
  276. })