if.spec.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import {
  2. children,
  3. createIf,
  4. insert,
  5. nextTick,
  6. ref,
  7. renderEffect,
  8. setText,
  9. template,
  10. withDirectives,
  11. } from '../src'
  12. import type { Mock } from 'vitest'
  13. import { makeRender } from './_utils'
  14. import { unmountComponent } from '../src/component'
  15. const define = makeRender()
  16. describe.todo('createIf', () => {
  17. test('basic', async () => {
  18. // mock this template:
  19. // <div>
  20. // <p v-if="counter">{{counter}}</p>
  21. // <p v-else>zero</p>
  22. // </div>
  23. let spyIfFn: Mock<any>
  24. let spyElseFn: Mock<any>
  25. const count = ref(0)
  26. const spyConditionFn = vi.fn(() => count.value)
  27. // templates can be reused through caching.
  28. const t0 = template('<div></div>')
  29. const t1 = template('<p></p>')
  30. const t2 = template('<p>zero</p>')
  31. const { host } = define(() => {
  32. const n0 = t0()
  33. insert(
  34. createIf(
  35. spyConditionFn,
  36. // v-if
  37. (spyIfFn ||= vi.fn(() => {
  38. const n2 = t1()
  39. renderEffect(() => {
  40. setText(n2, count.value)
  41. })
  42. return n2
  43. })),
  44. // v-else
  45. (spyElseFn ||= vi.fn(() => {
  46. const n4 = t2()
  47. return n4
  48. })),
  49. ),
  50. n0 as any as ParentNode,
  51. )
  52. return n0
  53. }).render()
  54. expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
  55. expect(spyConditionFn).toHaveBeenCalledTimes(1)
  56. expect(spyIfFn!).toHaveBeenCalledTimes(0)
  57. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  58. count.value++
  59. await nextTick()
  60. expect(host.innerHTML).toBe('<div><p>1</p><!--if--></div>')
  61. expect(spyConditionFn).toHaveBeenCalledTimes(2)
  62. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  63. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  64. count.value++
  65. await nextTick()
  66. expect(host.innerHTML).toBe('<div><p>2</p><!--if--></div>')
  67. expect(spyConditionFn).toHaveBeenCalledTimes(3)
  68. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  69. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  70. count.value = 0
  71. await nextTick()
  72. expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
  73. expect(spyConditionFn).toHaveBeenCalledTimes(4)
  74. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  75. expect(spyElseFn!).toHaveBeenCalledTimes(2)
  76. })
  77. test('should handle nested template', async () => {
  78. // mock this template:
  79. // <template v-if="ok1">
  80. // Hello <template v-if="ok2">Vapor</template>
  81. // </template>
  82. const ok1 = ref(true)
  83. const ok2 = ref(true)
  84. const t0 = template('Vapor')
  85. const t1 = template('Hello ')
  86. const { host } = define(() => {
  87. const n1 = createIf(
  88. () => ok1.value,
  89. () => {
  90. const n2 = t1()
  91. const n3 = createIf(
  92. () => ok2.value,
  93. () => {
  94. const n4 = t0()
  95. return n4
  96. },
  97. )
  98. return [n2, n3]
  99. },
  100. )
  101. return n1
  102. }).render()
  103. expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
  104. ok1.value = false
  105. await nextTick()
  106. expect(host.innerHTML).toBe('<!--if-->')
  107. ok1.value = true
  108. await nextTick()
  109. expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
  110. ok2.value = false
  111. await nextTick()
  112. expect(host.innerHTML).toBe('Hello <!--if--><!--if-->')
  113. ok1.value = false
  114. await nextTick()
  115. expect(host.innerHTML).toBe('<!--if-->')
  116. })
  117. test.todo('should work with directive hooks', async () => {
  118. const calls: string[] = []
  119. const show1 = ref(true)
  120. const show2 = ref(true)
  121. const update = ref(0)
  122. const spyConditionFn1 = vi.fn(() => show1.value)
  123. const spyConditionFn2 = vi.fn(() => show2.value)
  124. const vDirective: any = {
  125. created: (el: any, { value }: any) => calls.push(`${value} created`),
  126. beforeMount: (el: any, { value }: any) =>
  127. calls.push(`${value} beforeMount`),
  128. mounted: (el: any, { value }: any) => calls.push(`${value} mounted`),
  129. beforeUpdate: (el: any, { value }: any) =>
  130. calls.push(`${value} beforeUpdate`),
  131. updated: (el: any, { value }: any) => calls.push(`${value} updated`),
  132. beforeUnmount: (el: any, { value }: any) =>
  133. calls.push(`${value} beforeUnmount`),
  134. unmounted: (el: any, { value }: any) => calls.push(`${value} unmounted`),
  135. }
  136. const t0 = template('<p></p>')
  137. const { instance } = define(() => {
  138. const n1 = createIf(
  139. spyConditionFn1,
  140. () => {
  141. const n2 = t0()
  142. withDirectives(children(n2, 0), [
  143. [vDirective, () => (update.value, '1')],
  144. ])
  145. return n2
  146. },
  147. () =>
  148. createIf(
  149. spyConditionFn2,
  150. () => {
  151. const n2 = t0()
  152. withDirectives(children(n2, 0), [[vDirective, () => '2']])
  153. return n2
  154. },
  155. () => {
  156. const n2 = t0()
  157. withDirectives(children(n2, 0), [[vDirective, () => '3']])
  158. return n2
  159. },
  160. ),
  161. )
  162. return [n1]
  163. }).render()
  164. await nextTick()
  165. expect(calls).toEqual(['1 created', '1 beforeMount', '1 mounted'])
  166. calls.length = 0
  167. expect(spyConditionFn1).toHaveBeenCalledTimes(1)
  168. expect(spyConditionFn2).toHaveBeenCalledTimes(0)
  169. show1.value = false
  170. await nextTick()
  171. expect(calls).toEqual([
  172. '1 beforeUnmount',
  173. '2 created',
  174. '2 beforeMount',
  175. '1 unmounted',
  176. '2 mounted',
  177. ])
  178. calls.length = 0
  179. expect(spyConditionFn1).toHaveBeenCalledTimes(2)
  180. expect(spyConditionFn2).toHaveBeenCalledTimes(1)
  181. show2.value = false
  182. await nextTick()
  183. expect(calls).toEqual([
  184. '2 beforeUnmount',
  185. '3 created',
  186. '3 beforeMount',
  187. '2 unmounted',
  188. '3 mounted',
  189. ])
  190. calls.length = 0
  191. expect(spyConditionFn1).toHaveBeenCalledTimes(2)
  192. expect(spyConditionFn2).toHaveBeenCalledTimes(2)
  193. show1.value = true
  194. await nextTick()
  195. expect(calls).toEqual([
  196. '3 beforeUnmount',
  197. '1 created',
  198. '1 beforeMount',
  199. '3 unmounted',
  200. '1 mounted',
  201. ])
  202. calls.length = 0
  203. expect(spyConditionFn1).toHaveBeenCalledTimes(3)
  204. expect(spyConditionFn2).toHaveBeenCalledTimes(2)
  205. update.value++
  206. await nextTick()
  207. expect(calls).toEqual(['1 beforeUpdate', '1 updated'])
  208. calls.length = 0
  209. expect(spyConditionFn1).toHaveBeenCalledTimes(3)
  210. expect(spyConditionFn2).toHaveBeenCalledTimes(2)
  211. unmountComponent(instance!)
  212. expect(calls).toEqual(['1 beforeUnmount', '1 unmounted'])
  213. expect(spyConditionFn1).toHaveBeenCalledTimes(3)
  214. expect(spyConditionFn2).toHaveBeenCalledTimes(2)
  215. })
  216. })