testRuntime.spec.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. } from '../src'
  17. import { mockWarn } from '@vue/shared'
  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. boolean: ''
  113. },
  114. [h('span', 'foo'), 'hello']
  115. )
  116. }
  117. }
  118. const root = nodeOps.createElement('div')
  119. render(h(App), root)
  120. expect(serialize(root)).toEqual(
  121. `<div><div id="test" boolean><span>foo</span>hello</div></div>`
  122. )
  123. // indented output
  124. expect(serialize(root, 2)).toEqual(
  125. `<div>
  126. <div id="test" boolean>
  127. <span>
  128. foo
  129. </span>
  130. hello
  131. </div>
  132. </div>`
  133. )
  134. })
  135. it('should be able to trigger events', async () => {
  136. const count = ref(0)
  137. const App = () => {
  138. return h(
  139. 'span',
  140. {
  141. onClick: () => {
  142. count.value++
  143. }
  144. },
  145. count.value
  146. )
  147. }
  148. const root = nodeOps.createElement('div')
  149. render(h(App), root)
  150. triggerEvent(root.children[0] as TestElement, 'click')
  151. expect(count.value).toBe(1)
  152. await nextTick()
  153. expect(serialize(root)).toBe(`<div><span>1</span></div>`)
  154. })
  155. it('should be able to trigger events with multiple listeners', async () => {
  156. const count = ref(0)
  157. const count2 = ref(1)
  158. const App = () => {
  159. return h(
  160. 'span',
  161. {
  162. onClick: [
  163. () => {
  164. count.value++
  165. },
  166. () => {
  167. count2.value++
  168. }
  169. ]
  170. },
  171. `${count.value}, ${count2.value}`
  172. )
  173. }
  174. const root = nodeOps.createElement('div')
  175. render(h(App), root)
  176. triggerEvent(root.children[0] as TestElement, 'click')
  177. expect(count.value).toBe(1)
  178. expect(count2.value).toBe(2)
  179. await nextTick()
  180. expect(serialize(root)).toBe(`<div><span>1, 2</span></div>`)
  181. })
  182. it('should mock warn', () => {
  183. console.warn('warn!!!')
  184. expect('warn!!!').toHaveBeenWarned()
  185. expect('warn!!!').toHaveBeenWarnedTimes(1)
  186. console.warn('warn!!!')
  187. expect('warn!!!').toHaveBeenWarnedTimes(2)
  188. console.warn('warning')
  189. expect('warn!!!').toHaveBeenWarnedTimes(2)
  190. expect('warning').toHaveBeenWarnedLast()
  191. })
  192. })