testRuntime.spec.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import {
  2. NodeOpTypes,
  3. type TestElement,
  4. TestNodeTypes,
  5. type TestText,
  6. dumpOps,
  7. h,
  8. nextTick,
  9. nodeOps,
  10. reactive,
  11. ref,
  12. render,
  13. resetOps,
  14. serialize,
  15. triggerEvent,
  16. } from '../src'
  17. describe('test renderer', () => {
  18. it('should work', () => {
  19. const root = nodeOps.createElement('div')
  20. render(
  21. h(
  22. 'div',
  23. {
  24. id: 'test',
  25. },
  26. 'hello',
  27. ),
  28. root,
  29. )
  30. expect(root.children.length).toBe(1)
  31. const el = root.children[0] as TestElement
  32. expect(el.type).toBe(TestNodeTypes.ELEMENT)
  33. expect(el.props.id).toBe('test')
  34. expect(el.children.length).toBe(1)
  35. const text = el.children[0] as TestText
  36. expect(text.type).toBe(TestNodeTypes.TEXT)
  37. expect(text.text).toBe('hello')
  38. })
  39. it('should record ops', async () => {
  40. const state = reactive({
  41. id: 'test',
  42. text: 'hello',
  43. })
  44. const App = {
  45. render() {
  46. return h(
  47. 'div',
  48. {
  49. id: state.id,
  50. },
  51. state.text,
  52. )
  53. },
  54. }
  55. const root = nodeOps.createElement('div')
  56. resetOps()
  57. render(h(App), root)
  58. const ops = dumpOps()
  59. expect(ops.length).toBe(4)
  60. expect(ops[0]).toEqual({
  61. type: NodeOpTypes.CREATE,
  62. nodeType: TestNodeTypes.ELEMENT,
  63. tag: 'div',
  64. targetNode: root.children[0],
  65. })
  66. expect(ops[1]).toEqual({
  67. type: NodeOpTypes.SET_ELEMENT_TEXT,
  68. text: 'hello',
  69. targetNode: root.children[0],
  70. })
  71. expect(ops[2]).toEqual({
  72. type: NodeOpTypes.PATCH,
  73. targetNode: root.children[0],
  74. propKey: 'id',
  75. propPrevValue: null,
  76. propNextValue: 'test',
  77. })
  78. expect(ops[3]).toEqual({
  79. type: NodeOpTypes.INSERT,
  80. targetNode: root.children[0],
  81. parentNode: root,
  82. refNode: null,
  83. })
  84. // test update ops
  85. state.id = 'foo'
  86. state.text = 'bar'
  87. await nextTick()
  88. const updateOps = dumpOps()
  89. expect(updateOps.length).toBe(2)
  90. expect(updateOps[0]).toEqual({
  91. type: NodeOpTypes.SET_ELEMENT_TEXT,
  92. targetNode: root.children[0],
  93. text: 'bar',
  94. })
  95. expect(updateOps[1]).toEqual({
  96. type: NodeOpTypes.PATCH,
  97. targetNode: root.children[0],
  98. propKey: 'id',
  99. propPrevValue: 'test',
  100. propNextValue: 'foo',
  101. })
  102. })
  103. it('should be able to serialize nodes', () => {
  104. const App = {
  105. render() {
  106. return h(
  107. 'div',
  108. {
  109. id: 'test',
  110. boolean: '',
  111. },
  112. [h('span', 'foo'), 'hello'],
  113. )
  114. },
  115. }
  116. const root = nodeOps.createElement('div')
  117. render(h(App), root)
  118. expect(serialize(root)).toEqual(
  119. `<div><div id="test" boolean><span>foo</span>hello</div></div>`,
  120. )
  121. // indented output
  122. expect(serialize(root, 2)).toEqual(
  123. `<div>
  124. <div id="test" boolean>
  125. <span>
  126. foo
  127. </span>
  128. hello
  129. </div>
  130. </div>`,
  131. )
  132. })
  133. it('should be able to trigger events', async () => {
  134. const count = ref(0)
  135. const App = () => {
  136. return h(
  137. 'span',
  138. {
  139. onClick: () => {
  140. count.value++
  141. },
  142. },
  143. count.value,
  144. )
  145. }
  146. const root = nodeOps.createElement('div')
  147. render(h(App), root)
  148. triggerEvent(root.children[0] as TestElement, 'click')
  149. expect(count.value).toBe(1)
  150. await nextTick()
  151. expect(serialize(root)).toBe(`<div><span>1</span></div>`)
  152. })
  153. it('should be able to trigger events with multiple listeners', async () => {
  154. const count = ref(0)
  155. const count2 = ref(1)
  156. const App = () => {
  157. return h(
  158. 'span',
  159. {
  160. onClick: [
  161. () => {
  162. count.value++
  163. },
  164. () => {
  165. count2.value++
  166. },
  167. ],
  168. },
  169. `${count.value}, ${count2.value}`,
  170. )
  171. }
  172. const root = nodeOps.createElement('div')
  173. render(h(App), root)
  174. triggerEvent(root.children[0] as TestElement, 'click')
  175. expect(count.value).toBe(1)
  176. expect(count2.value).toBe(2)
  177. await nextTick()
  178. expect(serialize(root)).toBe(`<div><span>1, 2</span></div>`)
  179. })
  180. })