apiLifecycle.spec.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import {
  2. type InjectionKey,
  3. type Ref,
  4. createComponent,
  5. createTextNode,
  6. getCurrentInstance,
  7. inject,
  8. nextTick,
  9. onRenderTracked,
  10. onRenderTriggered,
  11. onUpdated,
  12. provide,
  13. ref,
  14. renderEffect,
  15. setText,
  16. } from '../src'
  17. import { makeRender } from './_utils'
  18. const define = makeRender<any>()
  19. describe('apiLifecycle', () => {
  20. // TODO: test
  21. // #136
  22. test('should trigger updated hooks across components. (parent -> child)', async () => {
  23. const handleUpdated = vi.fn()
  24. const handleUpdatedChild = vi.fn()
  25. const count = ref(0)
  26. const { render, host } = define({
  27. setup() {
  28. onUpdated(() => handleUpdated())
  29. return (() => {
  30. const n0 = createTextNode()
  31. renderEffect(() => setText(n0, count.value))
  32. const n1 = createComponent(Child, { count: () => count.value })
  33. return [n0, n1]
  34. })()
  35. },
  36. })
  37. const Child = {
  38. props: { count: Number },
  39. setup() {
  40. onUpdated(() => handleUpdatedChild())
  41. return (() => {
  42. const props = getCurrentInstance()!.props
  43. const n2 = createTextNode()
  44. renderEffect(() => setText(n2, props.count))
  45. return n2
  46. })()
  47. },
  48. }
  49. render()
  50. expect(host.innerHTML).toBe('00')
  51. expect(handleUpdated).toHaveBeenCalledTimes(0)
  52. expect(handleUpdatedChild).toHaveBeenCalledTimes(0)
  53. count.value++
  54. await nextTick()
  55. expect(host.innerHTML).toBe('11')
  56. expect(handleUpdated).toHaveBeenCalledTimes(1)
  57. expect(handleUpdatedChild).toHaveBeenCalledTimes(1)
  58. })
  59. // #136
  60. test('should trigger updated hooks across components. (child -> parent)', async () => {
  61. const handleUpdated = vi.fn()
  62. const handleUpdatedChild = vi.fn()
  63. const key: InjectionKey<Ref<number>> = Symbol()
  64. const { render, host } = define({
  65. setup() {
  66. const count = ref(0)
  67. provide(key, count)
  68. onUpdated(() => handleUpdated())
  69. return (() => {
  70. const n0 = createTextNode()
  71. renderEffect(() => setText(n0, count.value))
  72. const n1 = createComponent(Child, { count: () => count.value })
  73. return [n0, n1]
  74. })()
  75. },
  76. })
  77. let update: any
  78. const Child = {
  79. props: { count: Number },
  80. setup() {
  81. onUpdated(() => handleUpdatedChild())
  82. const count = inject(key)!
  83. update = () => count.value++
  84. return (() => {
  85. const n2 = createTextNode()
  86. renderEffect(() => setText(n2, count.value))
  87. return n2
  88. })()
  89. },
  90. }
  91. render()
  92. expect(host.innerHTML).toBe('00')
  93. expect(handleUpdated).toHaveBeenCalledTimes(0)
  94. expect(handleUpdatedChild).toHaveBeenCalledTimes(0)
  95. update()
  96. await nextTick()
  97. expect(host.innerHTML).toBe('11')
  98. expect(handleUpdated).toHaveBeenCalledTimes(1)
  99. expect(handleUpdatedChild).toHaveBeenCalledTimes(1)
  100. })
  101. test('onRenderTracked', async () => {
  102. const onTrackedFn = vi.fn()
  103. const count = ref(0)
  104. const { host, render } = define({
  105. setup() {
  106. onRenderTracked(onTrackedFn)
  107. return (() => {
  108. const n0 = createTextNode()
  109. renderEffect(() => {
  110. setText(n0, count.value)
  111. })
  112. return n0
  113. })()
  114. },
  115. })
  116. render()
  117. await nextTick()
  118. expect(onTrackedFn).toBeCalled()
  119. expect(host.innerHTML).toBe('0')
  120. })
  121. test('onRenderTrigger', async () => {
  122. const onRenderTriggerFn = vi.fn()
  123. const count = ref(0)
  124. const { host, render } = define({
  125. setup() {
  126. onRenderTriggered(onRenderTriggerFn)
  127. return (() => {
  128. const n0 = createTextNode()
  129. renderEffect(() => {
  130. setText(n0, count.value)
  131. })
  132. return n0
  133. })()
  134. },
  135. })
  136. render()
  137. count.value++
  138. await nextTick()
  139. expect(onRenderTriggerFn).toBeCalled()
  140. expect(onRenderTriggerFn).toHaveBeenCalledOnce()
  141. expect(host.innerHTML).toBe('1')
  142. })
  143. })