testRuntime.spec.ts 4.4 KB

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