2
0

create-component.spec.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import Vue from 'vue'
  2. import { createComponent } from 'core/vdom/create-component'
  3. import { setCurrentRenderingInstance } from 'core/instance/render'
  4. describe('create-component', () => {
  5. let vm
  6. beforeEach(() => {
  7. vm = new Vue({
  8. template: '<p>{{msg}}</p>',
  9. data() {
  10. return { msg: 'hello, my children' }
  11. }
  12. }).$mount()
  13. return new Promise(r => Vue.nextTick(r))
  14. })
  15. it('create a component basically', () => {
  16. const child = {
  17. name: 'child',
  18. props: ['msg'],
  19. render() {}
  20. }
  21. const data = {
  22. props: { msg: 'hello world' },
  23. attrs: { id: 1 },
  24. staticAttrs: { class: 'foo' },
  25. on: { notify: 'onNotify' }
  26. }
  27. const vnode = createComponent(child, data, vm, vm)
  28. expect(vnode.tag).toMatch(/vue-component-[0-9]+-child/)
  29. expect(vnode.data.attrs).toEqual({ id: 1 })
  30. expect(vnode.data.staticAttrs).toEqual({ class: 'foo' })
  31. expect(vnode.componentOptions.propsData).toEqual({ msg: 'hello world' })
  32. expect(vnode.componentOptions.listeners).toEqual({ notify: 'onNotify' })
  33. expect(vnode.children).toBeUndefined()
  34. expect(vnode.text).toBeUndefined()
  35. expect(vnode.elm).toBeUndefined()
  36. expect(vnode.ns).toBeUndefined()
  37. expect(vnode.context).toEqual(vm)
  38. })
  39. it('create a component when resolved with async loading', done => {
  40. let vnode = null
  41. const data = {
  42. props: {},
  43. staticAttrs: { class: 'foo' }
  44. }
  45. vi.spyOn(vm, '$forceUpdate')
  46. function async(resolve, reject) {
  47. setTimeout(() => {
  48. resolve({
  49. name: 'child',
  50. props: ['msg']
  51. })
  52. Vue.nextTick(loaded)
  53. }, 0)
  54. }
  55. function go() {
  56. setCurrentRenderingInstance(vm)
  57. vnode = createComponent(async, data, vm, vm)
  58. setCurrentRenderingInstance(null)
  59. expect(vnode.isComment).toBe(true) // not to be loaded yet.
  60. expect(vnode.asyncFactory).toBe(async)
  61. expect(vnode.asyncFactory.owners.length).toEqual(1)
  62. }
  63. function loaded() {
  64. setCurrentRenderingInstance(vm)
  65. vnode = createComponent(async, data, vm, vm)
  66. setCurrentRenderingInstance(null)
  67. expect(vnode.tag).toMatch(/vue-component-[0-9]+-child/)
  68. expect(vnode.data.staticAttrs).toEqual({ class: 'foo' })
  69. expect(vnode.children).toBeUndefined()
  70. expect(vnode.text).toBeUndefined()
  71. expect(vnode.elm).toBeUndefined()
  72. expect(vnode.ns).toBeUndefined()
  73. expect(vnode.context).toEqual(vm)
  74. expect(vnode.asyncFactory.owners.length).toEqual(0)
  75. expect(vm.$forceUpdate).toHaveBeenCalled()
  76. done()
  77. }
  78. go()
  79. })
  80. it('create a component when resolved with synchronous async loading', done => {
  81. const data = {
  82. props: {},
  83. staticAttrs: { class: 'bar' }
  84. }
  85. vi.spyOn(vm, '$forceUpdate')
  86. function async(resolve, reject) {
  87. resolve({
  88. name: 'child',
  89. props: ['msg']
  90. })
  91. }
  92. setCurrentRenderingInstance(vm)
  93. const vnode = createComponent(async, data, vm, vm)
  94. setCurrentRenderingInstance(null)
  95. expect(vnode.asyncFactory).toBe(async)
  96. expect(vnode.asyncFactory.owners.length).toEqual(0)
  97. expect(vnode.tag).toMatch(/vue-component-[0-9]+-child/)
  98. expect(vnode.data.staticAttrs).toEqual({ class: 'bar' })
  99. expect(vnode.children).toBeUndefined()
  100. expect(vnode.text).toBeUndefined()
  101. expect(vnode.elm).toBeUndefined()
  102. expect(vnode.ns).toBeUndefined()
  103. expect(vnode.context).toEqual(vm)
  104. expect(vm.$forceUpdate).not.toHaveBeenCalled()
  105. done()
  106. })
  107. it('not create a component when rejected with async loading', done => {
  108. let vnode = null
  109. const data = {
  110. props: { msg: 'hello world' },
  111. attrs: { id: 1 }
  112. }
  113. const reason = 'failed!!'
  114. function async(resolve, reject) {
  115. setTimeout(() => {
  116. reject(reason)
  117. Vue.nextTick(failed)
  118. }, 0)
  119. }
  120. function go() {
  121. setCurrentRenderingInstance(vm)
  122. vnode = createComponent(async, data, vm, vm)
  123. setCurrentRenderingInstance(null)
  124. expect(vnode.isComment).toBe(true) // not to be loaded yet.
  125. }
  126. function failed() {
  127. setCurrentRenderingInstance(vm)
  128. vnode = createComponent(async, data, vm, vm)
  129. setCurrentRenderingInstance(null)
  130. expect(vnode.isComment).toBe(true) // failed, still a comment node
  131. expect(
  132. `Failed to resolve async component: ${async}\nReason: ${reason}`
  133. ).toHaveBeenWarned()
  134. done()
  135. }
  136. go()
  137. })
  138. it('not create a component when specified with falsy', () => {
  139. const vnode = createComponent(null, {}, vm, vm)
  140. expect(vnode).toBeUndefined()
  141. })
  142. it('warn component definition type', () => {
  143. const Ctor = 'child'
  144. const vnode = createComponent(Ctor, {}, vm, vm)
  145. expect(vnode).toBeUndefined()
  146. expect(`Invalid Component definition: ${Ctor}`).toHaveBeenWarned()
  147. })
  148. })