create-element.spec.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. // #6642
  133. it('render svg foreignObject component with correct namespace', () => {
  134. const vm = new Vue({
  135. template: `
  136. <svg>
  137. <test></test>
  138. </svg>
  139. `,
  140. components: {
  141. test: {
  142. template: `
  143. <foreignObject>
  144. <p xmlns="http://www.w3.org/1999/xhtml"></p>
  145. </foreignObject>
  146. `
  147. }
  148. }
  149. }).$mount()
  150. const testComp = vm.$children[0]
  151. expect(testComp.$vnode.ns).toBe('svg')
  152. expect(testComp._vnode.tag).toBe('foreignObject')
  153. expect(testComp._vnode.ns).toBe('svg')
  154. expect(testComp._vnode.children[0].tag).toBe('p')
  155. expect(testComp._vnode.children[0].ns).toBeUndefined()
  156. })
  157. // #6506
  158. it('render SVGAElement in a component correctly', () => {
  159. const vm = new Vue({
  160. template: `
  161. <svg>
  162. <test></test>
  163. </svg>
  164. `,
  165. components: {
  166. test: { render: h => h('a') }
  167. }
  168. }).$mount()
  169. const testComp = vm.$children[0]
  170. expect(testComp.$vnode.ns).toBe('svg')
  171. expect(testComp._vnode.tag).toBe('a')
  172. expect(testComp._vnode.ns).toBe('svg')
  173. })
  174. it('warn observed data objects', () => {
  175. new Vue({
  176. data: {
  177. data: {}
  178. },
  179. render (h) {
  180. return h('div', this.data)
  181. }
  182. }).$mount()
  183. expect('Avoid using observed data object as vnode data').toHaveBeenWarned()
  184. })
  185. it('warn non-primitive key', () => {
  186. new Vue({
  187. render (h) {
  188. return h('div', { key: {}})
  189. }
  190. }).$mount()
  191. expect('Avoid using non-primitive value as key').toHaveBeenWarned()
  192. })
  193. it('doesn\'t warn boolean key', () => {
  194. new Vue({
  195. render (h) {
  196. return h('div', { key: true })
  197. }
  198. }).$mount()
  199. expect('Avoid using non-primitive value as key').not.toHaveBeenWarned()
  200. })
  201. it('nested child elements should be updated correctly', done => {
  202. const vm = new Vue({
  203. data: { n: 1 },
  204. render (h) {
  205. const list = []
  206. for (let i = 0; i < this.n; i++) {
  207. list.push(h('span', i))
  208. }
  209. const input = h('input', {
  210. attrs: {
  211. value: 'a',
  212. type: 'text'
  213. }
  214. })
  215. return h('div', [[...list, input]])
  216. }
  217. }).$mount()
  218. expect(vm.$el.innerHTML).toContain('<span>0</span><input')
  219. const el = vm.$el.querySelector('input')
  220. el.value = 'b'
  221. vm.n++
  222. waitForUpdate(() => {
  223. expect(vm.$el.innerHTML).toContain('<span>0</span><span>1</span><input')
  224. expect(vm.$el.querySelector('input')).toBe(el)
  225. expect(vm.$el.querySelector('input').value).toBe('b')
  226. }).then(done)
  227. })
  228. })