2
0

async_component_spec.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. var Vue = require('src')
  2. var _ = Vue.util
  3. describe('Async components', function () {
  4. var el
  5. beforeEach(function () {
  6. el = document.createElement('div')
  7. document.body.appendChild(el)
  8. spyWarns()
  9. })
  10. afterEach(function () {
  11. document.body.removeChild(el)
  12. })
  13. it('normal', function (done) {
  14. var go = jasmine.createSpy()
  15. new Vue({
  16. el: el,
  17. template: '<test hi="ok" @ready="go"></test>',
  18. methods: {
  19. go: go
  20. },
  21. components: {
  22. test: function (resolve) {
  23. setTimeout(function () {
  24. resolve({
  25. props: ['hi'],
  26. template: '{{ hi }}',
  27. ready: function () {
  28. this.$emit('ready')
  29. }
  30. })
  31. next()
  32. }, 0)
  33. }
  34. }
  35. })
  36. function next () {
  37. expect(el.textContent).toBe('ok')
  38. expect(go).toHaveBeenCalled()
  39. done()
  40. }
  41. })
  42. it('dynamic', function (done) {
  43. var vm = new Vue({
  44. el: el,
  45. template: '<component :is="view"></component>',
  46. data: {
  47. view: 'view-a'
  48. },
  49. components: {
  50. 'view-a': function (resolve) {
  51. setTimeout(function () {
  52. resolve({
  53. template: 'A'
  54. })
  55. step1()
  56. }, 0)
  57. },
  58. 'view-b': function (resolve) {
  59. setTimeout(function () {
  60. resolve({
  61. template: 'B'
  62. })
  63. step2()
  64. }, 0)
  65. }
  66. }
  67. })
  68. var aCalled = false
  69. function step1 () {
  70. // ensure A is resolved only once
  71. expect(aCalled).toBe(false)
  72. aCalled = true
  73. expect(el.textContent).toBe('A')
  74. vm.view = 'view-b'
  75. }
  76. function step2 () {
  77. expect(el.textContent).toBe('B')
  78. vm.view = 'view-a'
  79. _.nextTick(function () {
  80. expect(el.textContent).toBe('A')
  81. done()
  82. })
  83. }
  84. })
  85. it('invalidate pending on dynamic switch', function (done) {
  86. var vm = new Vue({
  87. el: el,
  88. template: '<component :is="view"></component>',
  89. data: {
  90. view: 'view-a'
  91. },
  92. components: {
  93. 'view-a': function (resolve) {
  94. setTimeout(function () {
  95. resolve({
  96. template: 'A'
  97. })
  98. step1()
  99. }, 100)
  100. },
  101. 'view-b': function (resolve) {
  102. setTimeout(function () {
  103. resolve({
  104. template: 'B'
  105. })
  106. step2()
  107. }, 200)
  108. }
  109. }
  110. })
  111. expect(el.textContent).toBe('')
  112. vm.view = 'view-b'
  113. function step1 () {
  114. // called after A resolves, but A should have been
  115. // invalidated so no Ctor should be set
  116. expect(vm._directives[0].Component).toBe(null)
  117. }
  118. function step2 () {
  119. // B should resolve successfully
  120. expect(el.textContent).toBe('B')
  121. done()
  122. }
  123. })
  124. it('invalidate pending on teardown', function (done) {
  125. var vm = new Vue({
  126. el: el,
  127. template: '<test></test>',
  128. data: {
  129. view: 'view-a'
  130. },
  131. components: {
  132. test: function (resolve) {
  133. setTimeout(function () {
  134. resolve({
  135. template: 'A'
  136. })
  137. next()
  138. }, 100)
  139. }
  140. }
  141. })
  142. expect(el.textContent).toBe('')
  143. // cache directive isntance before destroy
  144. var dir = vm._directives[0]
  145. vm.$destroy()
  146. function next () {
  147. // called after A resolves, but A should have been
  148. // invalidated so no Ctor should be set
  149. expect(dir.Component).toBe(null)
  150. done()
  151. }
  152. })
  153. it('avoid duplicate requests', function (done) {
  154. var factoryCallCount = 0
  155. var instanceCount = 0
  156. new Vue({
  157. el: el,
  158. template:
  159. '<test></test>' +
  160. '<test></test>',
  161. components: {
  162. test: factory
  163. }
  164. })
  165. function factory (resolve) {
  166. factoryCallCount++
  167. setTimeout(function () {
  168. resolve({
  169. template: 'A',
  170. created: function () {
  171. instanceCount++
  172. }
  173. })
  174. next()
  175. }, 0)
  176. }
  177. function next () {
  178. expect(factoryCallCount).toBe(1)
  179. expect(el.textContent).toBe('AA')
  180. expect(instanceCount).toBe(2)
  181. done()
  182. }
  183. })
  184. it('warn reject', function () {
  185. new Vue({
  186. el: el,
  187. template: '<test></test>',
  188. components: {
  189. test: function (resolve, reject) {
  190. reject('nooooo')
  191. }
  192. }
  193. })
  194. expect(hasWarned('Reason: nooooo')).toBe(true)
  195. })
  196. it('v-for', function (done) {
  197. new Vue({
  198. el: el,
  199. template: '<test v-for="n in list" :n="n"></test>',
  200. data: {
  201. list: [1, 2, 3]
  202. },
  203. components: {
  204. test: function (resolve) {
  205. setTimeout(function () {
  206. resolve({
  207. props: ['n'],
  208. template: '{{n}}'
  209. })
  210. next()
  211. }, 0)
  212. }
  213. }
  214. })
  215. function next () {
  216. expect(el.textContent).toBe('123')
  217. done()
  218. }
  219. })
  220. })