create-element.spec.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import Vue from 'vue'
  2. import { createEmptyVNode } from 'core/vdom/vnode'
  3. describe('create-element', () => {
  4. it('render vnode with basic reserved tag using createElement', () => {
  5. const vm = new Vue({
  6. data: { msg: 'hello world' }
  7. })
  8. const h = vm.$createElement
  9. const vnode = h('p', {})
  10. expect(vnode.tag).toBe('p')
  11. expect(vnode.data).toEqual({})
  12. expect(vnode.children).toBeUndefined()
  13. expect(vnode.text).toBeUndefined()
  14. expect(vnode.elm).toBeUndefined()
  15. expect(vnode.ns).toBeUndefined()
  16. expect(vnode.context).toEqual(vm)
  17. })
  18. it('render vnode with component using createElement', () => {
  19. const vm = new Vue({
  20. data: { message: 'hello world' },
  21. components: {
  22. 'my-component': {
  23. props: ['msg']
  24. }
  25. }
  26. })
  27. const h = vm.$createElement
  28. const vnode = h('my-component', { props: { msg: vm.message }})
  29. expect(vnode.tag).toMatch(/vue-component-[0-9]+/)
  30. expect(vnode.componentOptions.propsData).toEqual({ msg: vm.message })
  31. expect(vnode.children).toBeUndefined()
  32. expect(vnode.text).toBeUndefined()
  33. expect(vnode.elm).toBeUndefined()
  34. expect(vnode.ns).toBeUndefined()
  35. expect(vnode.context).toEqual(vm)
  36. })
  37. it('render vnode with custom tag using createElement', () => {
  38. const vm = new Vue({
  39. data: { msg: 'hello world' }
  40. })
  41. const h = vm.$createElement
  42. const tag = 'custom-tag'
  43. const vnode = h(tag, {})
  44. expect(vnode.tag).toBe('custom-tag')
  45. expect(vnode.data).toEqual({})
  46. expect(vnode.children).toBeUndefined()
  47. expect(vnode.text).toBeUndefined()
  48. expect(vnode.elm).toBeUndefined()
  49. expect(vnode.ns).toBeUndefined()
  50. expect(vnode.context).toEqual(vm)
  51. expect(vnode.componentOptions).toBeUndefined()
  52. })
  53. it('render empty vnode with falsy tag using createElement', () => {
  54. const vm = new Vue({
  55. data: { msg: 'hello world' }
  56. })
  57. const h = vm.$createElement
  58. const vnode = h(null, {})
  59. expect(vnode).toEqual(createEmptyVNode())
  60. })
  61. it('render vnode with not string tag using createElement', () => {
  62. const vm = new Vue({
  63. data: { msg: 'hello world' }
  64. })
  65. const h = vm.$createElement
  66. const vnode = h(Vue.extend({ // Component class
  67. props: ['msg']
  68. }), { props: { msg: vm.message }})
  69. expect(vnode.tag).toMatch(/vue-component-[0-9]+/)
  70. expect(vnode.componentOptions.propsData).toEqual({ msg: vm.message })
  71. expect(vnode.children).toBeUndefined()
  72. expect(vnode.text).toBeUndefined()
  73. expect(vnode.elm).toBeUndefined()
  74. expect(vnode.ns).toBeUndefined()
  75. expect(vnode.context).toEqual(vm)
  76. })
  77. it('render vnode with createElement with children', () => {
  78. const vm = new Vue({})
  79. const h = vm.$createElement
  80. const vnode = h('p', void 0, [h('br'), 'hello world', h('br')])
  81. expect(vnode.children[0].tag).toBe('br')
  82. expect(vnode.children[1].text).toBe('hello world')
  83. expect(vnode.children[2].tag).toBe('br')
  84. })
  85. it('render vnode with children, omitting data', () => {
  86. const vm = new Vue({})
  87. const h = vm.$createElement
  88. const vnode = h('p', [h('br'), 'hello world', h('br')])
  89. expect(vnode.children[0].tag).toBe('br')
  90. expect(vnode.children[1].text).toBe('hello world')
  91. expect(vnode.children[2].tag).toBe('br')
  92. })
  93. it('render vnode with children, including boolean and null type', () => {
  94. const vm = new Vue({})
  95. const h = vm.$createElement
  96. const vnode = h('p', [h('br'), true, 123, h('br'), 'abc', null])
  97. expect(vnode.children.length).toBe(4)
  98. expect(vnode.children[0].tag).toBe('br')
  99. expect(vnode.children[1].text).toBe('123')
  100. expect(vnode.children[2].tag).toBe('br')
  101. expect(vnode.children[3].text).toBe('abc')
  102. })
  103. it('render svg elements with correct namespace', () => {
  104. const vm = new Vue({})
  105. const h = vm.$createElement
  106. const vnode = h('svg', [h('a', [h('foo', [h('bar')])])])
  107. expect(vnode.ns).toBe('svg')
  108. // should apply ns to children recursively
  109. expect(vnode.children[0].ns).toBe('svg')
  110. expect(vnode.children[0].children[0].ns).toBe('svg')
  111. expect(vnode.children[0].children[0].children[0].ns).toBe('svg')
  112. })
  113. it('render MathML elements with correct namespace', () => {
  114. const vm = new Vue({})
  115. const h = vm.$createElement
  116. const vnode = h('math', [h('matrix')])
  117. expect(vnode.ns).toBe('math')
  118. // should apply ns to children
  119. expect(vnode.children[0].ns).toBe('math')
  120. // although not explicitly listed, elements nested under <math>
  121. // should not be treated as component
  122. expect(vnode.children[0].componentOptions).toBeUndefined()
  123. })
  124. it('render svg foreignObject with correct namespace', () => {
  125. const vm = new Vue({})
  126. const h = vm.$createElement
  127. const vnode = h('svg', [h('foreignObject', [h('p')])])
  128. expect(vnode.ns).toBe('svg')
  129. expect(vnode.children[0].ns).toBe('svg')
  130. expect(vnode.children[0].children[0].ns).toBeUndefined()
  131. })
  132. // #6506
  133. it('render SVGAElement in a component correctly', () => {
  134. const vm = new Vue({
  135. template: `
  136. <svg>
  137. <test></test>
  138. </svg>
  139. `,
  140. components: {
  141. test: { render: h => h('a') }
  142. }
  143. }).$mount()
  144. const testComp = vm.$children[0]
  145. expect(testComp.$vnode.ns).toBe('svg')
  146. expect(testComp._vnode.tag).toBe('a')
  147. expect(testComp._vnode.ns).toBe('svg')
  148. })
  149. it('warn observed data objects', () => {
  150. new Vue({
  151. data: {
  152. data: {}
  153. },
  154. render (h) {
  155. return h('div', this.data)
  156. }
  157. }).$mount()
  158. expect('Avoid using observed data object as vnode data').toHaveBeenWarned()
  159. })
  160. it('warn non-primitive key', () => {
  161. new Vue({
  162. render (h) {
  163. return h('div', { key: {}})
  164. }
  165. }).$mount()
  166. expect('Avoid using non-primitive value as key').toHaveBeenWarned()
  167. })
  168. it('doesn\'t warn boolean key', () => {
  169. new Vue({
  170. render (h) {
  171. return h('div', { key: true })
  172. }
  173. }).$mount()
  174. expect('Avoid using non-primitive value as key').not.toHaveBeenWarned()
  175. })
  176. it('nested child elements should be updated correctly', done => {
  177. const vm = new Vue({
  178. data: { n: 1 },
  179. render (h) {
  180. const list = []
  181. for (let i = 0; i < this.n; i++) {
  182. list.push(h('span', i))
  183. }
  184. const input = h('input', {
  185. attrs: {
  186. value: 'a',
  187. type: 'text'
  188. }
  189. })
  190. return h('div', [[...list, input]])
  191. }
  192. }).$mount()
  193. expect(vm.$el.innerHTML).toContain('<span>0</span><input')
  194. const el = vm.$el.querySelector('input')
  195. el.value = 'b'
  196. vm.n++
  197. waitForUpdate(() => {
  198. expect(vm.$el.innerHTML).toContain('<span>0</span><span>1</span><input')
  199. expect(vm.$el.querySelector('input')).toBe(el)
  200. expect(vm.$el.querySelector('input').value).toBe('b')
  201. }).then(done)
  202. })
  203. })