component-async.spec.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import Vue from 'vue'
  2. import { Promise } from 'es6-promise'
  3. describe('Component async', () => {
  4. it('normal', done => {
  5. const vm = new Vue({
  6. template: '<div><test></test></div>',
  7. components: {
  8. test: (resolve) => {
  9. setTimeout(() => {
  10. resolve({
  11. template: '<div>hi</div>'
  12. })
  13. // wait for parent update
  14. Vue.nextTick(next)
  15. }, 0)
  16. }
  17. }
  18. }).$mount()
  19. expect(vm.$el.innerHTML).toBe('<!---->')
  20. expect(vm.$children.length).toBe(0)
  21. function next () {
  22. expect(vm.$el.innerHTML).toBe('<div>hi</div>')
  23. expect(vm.$children.length).toBe(1)
  24. done()
  25. }
  26. })
  27. it('as root', done => {
  28. const vm = new Vue({
  29. template: '<test></test>',
  30. components: {
  31. test: resolve => {
  32. setTimeout(() => {
  33. resolve({
  34. template: '<div>hi</div>'
  35. })
  36. // wait for parent update
  37. Vue.nextTick(next)
  38. }, 0)
  39. }
  40. }
  41. }).$mount()
  42. expect(vm.$el.nodeType).toBe(8)
  43. expect(vm.$children.length).toBe(0)
  44. function next () {
  45. expect(vm.$el.nodeType).toBe(1)
  46. expect(vm.$el.outerHTML).toBe('<div>hi</div>')
  47. expect(vm.$children.length).toBe(1)
  48. done()
  49. }
  50. })
  51. it('dynamic', done => {
  52. var vm = new Vue({
  53. template: '<component :is="view"></component>',
  54. data: {
  55. view: 'view-a'
  56. },
  57. components: {
  58. 'view-a': resolve => {
  59. setTimeout(() => {
  60. resolve({
  61. template: '<div>A</div>'
  62. })
  63. Vue.nextTick(step1)
  64. }, 0)
  65. },
  66. 'view-b': resolve => {
  67. setTimeout(() => {
  68. resolve({
  69. template: '<p>B</p>'
  70. })
  71. Vue.nextTick(step2)
  72. }, 0)
  73. }
  74. }
  75. }).$mount()
  76. var aCalled = false
  77. function step1 () {
  78. // ensure A is resolved only once
  79. expect(aCalled).toBe(false)
  80. aCalled = true
  81. expect(vm.$el.tagName).toBe('DIV')
  82. expect(vm.$el.textContent).toBe('A')
  83. vm.view = 'view-b'
  84. }
  85. function step2 () {
  86. expect(vm.$el.tagName).toBe('P')
  87. expect(vm.$el.textContent).toBe('B')
  88. vm.view = 'view-a'
  89. waitForUpdate(function () {
  90. expect(vm.$el.tagName).toBe('DIV')
  91. expect(vm.$el.textContent).toBe('A')
  92. }).then(done)
  93. }
  94. })
  95. it('warn reject', () => {
  96. new Vue({
  97. template: '<test></test>',
  98. components: {
  99. test: (resolve, reject) => {
  100. reject('nooooo')
  101. }
  102. }
  103. }).$mount()
  104. expect('Reason: nooooo').toHaveBeenWarned()
  105. })
  106. it('with v-for', done => {
  107. const vm = new Vue({
  108. template: '<div><test v-for="n in list" :key="n" :n="n"></test></div>',
  109. data: {
  110. list: [1, 2, 3]
  111. },
  112. components: {
  113. test: resolve => {
  114. setTimeout(() => {
  115. resolve({
  116. props: ['n'],
  117. template: '<div>{{n}}</div>'
  118. })
  119. Vue.nextTick(next)
  120. }, 0)
  121. }
  122. }
  123. }).$mount()
  124. function next () {
  125. expect(vm.$el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div>')
  126. done()
  127. }
  128. })
  129. it('returning Promise', done => {
  130. const vm = new Vue({
  131. template: '<div><test></test></div>',
  132. components: {
  133. test: () => {
  134. return new Promise(resolve => {
  135. setTimeout(() => {
  136. resolve({
  137. template: '<div>hi</div>'
  138. })
  139. // wait for promise resolve and then parent update
  140. Promise.resolve().then(() => {
  141. Vue.nextTick(next)
  142. })
  143. }, 0)
  144. })
  145. }
  146. }
  147. }).$mount()
  148. expect(vm.$el.innerHTML).toBe('<!---->')
  149. expect(vm.$children.length).toBe(0)
  150. function next () {
  151. expect(vm.$el.innerHTML).toBe('<div>hi</div>')
  152. expect(vm.$children.length).toBe(1)
  153. done()
  154. }
  155. })
  156. describe('loading/error/timeout', () => {
  157. it('with loading component', done => {
  158. const vm = new Vue({
  159. template: `<div><test/></div>`,
  160. components: {
  161. test: () => ({
  162. component: new Promise(resolve => {
  163. setTimeout(() => {
  164. resolve({ template: '<div>hi</div>' })
  165. // wait for promise resolve and then parent update
  166. Promise.resolve().then(() => {
  167. Vue.nextTick(next)
  168. })
  169. }, 50)
  170. }),
  171. loading: { template: `<div>loading</div>` },
  172. delay: 1
  173. })
  174. }
  175. }).$mount()
  176. expect(vm.$el.innerHTML).toBe('<!---->')
  177. let loadingAsserted = false
  178. setTimeout(() => {
  179. Vue.nextTick(() => {
  180. loadingAsserted = true
  181. expect(vm.$el.textContent).toBe('loading')
  182. })
  183. }, 1)
  184. function next () {
  185. expect(loadingAsserted).toBe(true)
  186. expect(vm.$el.textContent).toBe('hi')
  187. done()
  188. }
  189. })
  190. it('with loading component (0 delay)', done => {
  191. const vm = new Vue({
  192. template: `<div><test/></div>`,
  193. components: {
  194. test: () => ({
  195. component: new Promise(resolve => {
  196. setTimeout(() => {
  197. resolve({ template: '<div>hi</div>' })
  198. // wait for promise resolve and then parent update
  199. Promise.resolve().then(() => {
  200. Vue.nextTick(next)
  201. })
  202. }, 50)
  203. }),
  204. loading: { template: `<div>loading</div>` },
  205. delay: 0
  206. })
  207. }
  208. }).$mount()
  209. expect(vm.$el.textContent).toBe('loading')
  210. function next () {
  211. expect(vm.$el.textContent).toBe('hi')
  212. done()
  213. }
  214. })
  215. it('with error component', done => {
  216. const vm = new Vue({
  217. template: `<div><test/></div>`,
  218. components: {
  219. test: () => ({
  220. component: new Promise((resolve, reject) => {
  221. setTimeout(() => {
  222. reject()
  223. // wait for promise resolve and then parent update
  224. Promise.resolve().then(() => {
  225. Vue.nextTick(next)
  226. })
  227. }, 50)
  228. }),
  229. loading: { template: `<div>loading</div>` },
  230. error: { template: `<div>error</div>` },
  231. delay: 0
  232. })
  233. }
  234. }).$mount()
  235. expect(vm.$el.textContent).toBe('loading')
  236. function next () {
  237. expect(`Failed to resolve async component`).toHaveBeenWarned()
  238. expect(vm.$el.textContent).toBe('error')
  239. done()
  240. }
  241. })
  242. it('with error component + timeout', done => {
  243. const vm = new Vue({
  244. template: `<div><test/></div>`,
  245. components: {
  246. test: () => ({
  247. component: new Promise((resolve, reject) => {
  248. setTimeout(() => {
  249. resolve({ template: '<div>hi</div>' })
  250. // wait for promise resolve and then parent update
  251. Promise.resolve().then(() => {
  252. Vue.nextTick(next)
  253. })
  254. }, 50)
  255. }),
  256. loading: { template: `<div>loading</div>` },
  257. error: { template: `<div>error</div>` },
  258. delay: 0,
  259. timeout: 1
  260. })
  261. }
  262. }).$mount()
  263. expect(vm.$el.textContent).toBe('loading')
  264. setTimeout(() => {
  265. Vue.nextTick(() => {
  266. expect(`Failed to resolve async component`).toHaveBeenWarned()
  267. expect(vm.$el.textContent).toBe('error')
  268. })
  269. }, 1)
  270. function next () {
  271. expect(vm.$el.textContent).toBe('error') // late resolve ignored
  272. done()
  273. }
  274. })
  275. it('should not trigger timeout if resolved', done => {
  276. const vm = new Vue({
  277. template: `<div><test/></div>`,
  278. components: {
  279. test: () => ({
  280. component: new Promise((resolve, reject) => {
  281. setTimeout(() => {
  282. resolve({ template: '<div>hi</div>' })
  283. }, 10)
  284. }),
  285. error: { template: `<div>error</div>` },
  286. timeout: 20
  287. })
  288. }
  289. }).$mount()
  290. setTimeout(() => {
  291. expect(vm.$el.textContent).toBe('hi')
  292. expect(`Failed to resolve async component`).not.toHaveBeenWarned()
  293. done()
  294. }, 30)
  295. })
  296. })
  297. })