if.spec.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { defineComponent } from 'vue'
  2. import {
  3. append,
  4. children,
  5. createIf,
  6. fragment,
  7. insert,
  8. nextTick,
  9. ref,
  10. render,
  11. renderEffect,
  12. setText,
  13. template,
  14. } from '../src'
  15. import type { Mock } from 'vitest'
  16. let host: HTMLElement
  17. const initHost = () => {
  18. host = document.createElement('div')
  19. host.setAttribute('id', 'host')
  20. document.body.appendChild(host)
  21. }
  22. beforeEach(() => {
  23. initHost()
  24. })
  25. afterEach(() => {
  26. host.remove()
  27. })
  28. describe('createIf', () => {
  29. test('basic', async () => {
  30. // mock this template:
  31. // <div>
  32. // <p v-if="counter">{{counter}}</p>
  33. // <p v-else>zero</p>
  34. // </div>
  35. let spyIfFn: Mock<any, any>
  36. let spyElseFn: Mock<any, any>
  37. const count = ref(0)
  38. // templates can be reused through caching.
  39. const t0 = template('<div></div>')
  40. const t1 = template('<p></p>')
  41. const t2 = template('<p>zero</p>')
  42. const component = defineComponent({
  43. setup() {
  44. // render
  45. return (() => {
  46. const n0 = t0()
  47. const {
  48. 0: [n1],
  49. } = children(n0)
  50. insert(
  51. createIf(
  52. () => count.value,
  53. // v-if
  54. (spyIfFn ||= vi.fn(() => {
  55. const n2 = t1()
  56. const {
  57. 0: [n3],
  58. } = children(n2)
  59. renderEffect(() => {
  60. setText(n3, count.value)
  61. })
  62. return n2
  63. })),
  64. // v-else
  65. (spyElseFn ||= vi.fn(() => {
  66. const n4 = t2()
  67. return n4
  68. })),
  69. ),
  70. n1 as any as ParentNode,
  71. )
  72. return n0
  73. })()
  74. },
  75. })
  76. render(component as any, {}, '#host')
  77. expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
  78. expect(spyIfFn!).toHaveBeenCalledTimes(0)
  79. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  80. count.value++
  81. await nextTick()
  82. expect(host.innerHTML).toBe('<div><p>1</p><!--if--></div>')
  83. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  84. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  85. count.value++
  86. await nextTick()
  87. expect(host.innerHTML).toBe('<div><p>2</p><!--if--></div>')
  88. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  89. expect(spyElseFn!).toHaveBeenCalledTimes(1)
  90. count.value = 0
  91. await nextTick()
  92. expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
  93. expect(spyIfFn!).toHaveBeenCalledTimes(1)
  94. expect(spyElseFn!).toHaveBeenCalledTimes(2)
  95. })
  96. test('should handle nested template', async () => {
  97. // mock this template:
  98. // <template v-if="ok1">
  99. // Hello <template v-if="ok2">Vapor</template>
  100. // </template>
  101. const ok1 = ref(true)
  102. const ok2 = ref(true)
  103. const t0 = template('Vapor')
  104. const t1 = template('Hello ')
  105. const t2 = fragment()
  106. render(
  107. defineComponent({
  108. setup() {
  109. // render
  110. return (() => {
  111. const n0 = t2()
  112. append(
  113. n0,
  114. createIf(
  115. () => ok1.value,
  116. () => {
  117. const n2 = t1()
  118. append(
  119. n2,
  120. createIf(
  121. () => ok2.value,
  122. () => t0(),
  123. ),
  124. )
  125. return n2
  126. },
  127. ),
  128. )
  129. return n0
  130. })()
  131. },
  132. }) as any,
  133. {},
  134. '#host',
  135. )
  136. expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
  137. ok1.value = false
  138. await nextTick()
  139. expect(host.innerHTML).toBe('<!--if-->')
  140. ok1.value = true
  141. await nextTick()
  142. expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
  143. ok2.value = false
  144. await nextTick()
  145. expect(host.innerHTML).toBe('Hello <!--if--><!--if-->')
  146. ok1.value = false
  147. await nextTick()
  148. expect(host.innerHTML).toBe('<!--if-->')
  149. })
  150. })