component_spec.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. var _ = require('../../../../src/util')
  2. var Vue = require('../../../../src/vue')
  3. if (_.inBrowser) {
  4. describe('v-component', function () {
  5. var el
  6. beforeEach(function () {
  7. el = document.createElement('div')
  8. spyOn(_, 'warn')
  9. })
  10. it('static', function () {
  11. var vm = new Vue({
  12. el: el,
  13. template: '<div v-component="test"></div>',
  14. components: {
  15. test: {
  16. data: function () {
  17. return { a: 123 }
  18. },
  19. template: '{{a}}'
  20. }
  21. }
  22. })
  23. expect(el.innerHTML).toBe('<div>123</div><!--v-component-->')
  24. })
  25. it('replace', function () {
  26. var vm = new Vue({
  27. el: el,
  28. template: '<div v-component="test"></div>',
  29. components: {
  30. test: {
  31. replace: true,
  32. data: function () {
  33. return { a: 123 }
  34. },
  35. template: '<p>{{a}}</p>'
  36. }
  37. }
  38. })
  39. expect(el.innerHTML).toBe('<p>123</p><!--v-component-->')
  40. })
  41. it('block replace', function () {
  42. var vm = new Vue({
  43. el: el,
  44. template: '<div v-component="test"></div>',
  45. components: {
  46. test: {
  47. replace: true,
  48. data: function () {
  49. return { a: 123, b: 234 }
  50. },
  51. template: '<p>{{a}}</p><p>{{b}}</p>'
  52. }
  53. }
  54. })
  55. expect(el.innerHTML).toBe('<!--v-start--><p>123</p><p>234</p><!--v-end--><!--v-component-->')
  56. })
  57. it('dynamic', function (done) {
  58. var vm = new Vue({
  59. el: el,
  60. template: '<div v-component="{{view}}" v-attr="view:view"></div>',
  61. data: {
  62. view: 'a'
  63. },
  64. components: {
  65. a: {
  66. template: 'AAA',
  67. data: function () {
  68. return { view: 'a' }
  69. }
  70. },
  71. b: {
  72. template: 'BBB',
  73. data: function () {
  74. return { view: 'b' }
  75. }
  76. }
  77. }
  78. })
  79. expect(el.innerHTML).toBe('<div view="a">AAA</div><!--v-component-->')
  80. vm.view = 'b'
  81. _.nextTick(function () {
  82. expect(el.innerHTML).toBe('<div view="b">BBB</div><!--v-component-->')
  83. vm.view = ''
  84. _.nextTick(function () {
  85. expect(el.innerHTML).toBe('<!--v-component-->')
  86. done()
  87. })
  88. })
  89. })
  90. it('keep-alive', function (done) {
  91. var spyA = jasmine.createSpy()
  92. var spyB = jasmine.createSpy()
  93. var vm = new Vue({
  94. el: el,
  95. template: '<div v-component="{{view}}" keep-alive></div>',
  96. data: {
  97. view: 'a'
  98. },
  99. components: {
  100. a: {
  101. created: spyA,
  102. template: 'AAA'
  103. },
  104. b: {
  105. created: spyB,
  106. template: 'BBB'
  107. }
  108. }
  109. })
  110. expect(el.innerHTML).toBe('<div>AAA</div><!--v-component-->')
  111. expect(spyA.calls.count()).toBe(1)
  112. expect(spyB.calls.count()).toBe(0)
  113. vm.view = 'b'
  114. _.nextTick(function () {
  115. expect(el.innerHTML).toBe('<div>BBB</div><!--v-component-->')
  116. expect(spyA.calls.count()).toBe(1)
  117. expect(spyB.calls.count()).toBe(1)
  118. vm.view = 'a'
  119. _.nextTick(function () {
  120. expect(el.innerHTML).toBe('<div>AAA</div><!--v-component-->')
  121. expect(spyA.calls.count()).toBe(1)
  122. expect(spyB.calls.count()).toBe(1)
  123. vm.view = 'b'
  124. _.nextTick(function () {
  125. expect(el.innerHTML).toBe('<div>BBB</div><!--v-component-->')
  126. expect(spyA.calls.count()).toBe(1)
  127. expect(spyB.calls.count()).toBe(1)
  128. done()
  129. })
  130. })
  131. })
  132. })
  133. it('should compile parent template directives & content in parent scope', function (done) {
  134. var vm = new Vue({
  135. el: el,
  136. data: {
  137. ok: false,
  138. message: 'hello'
  139. },
  140. template: '<div v-component="test" v-show="ok">{{message}}</div>',
  141. components: {
  142. test: {
  143. template: '<content></content> {{message}}',
  144. data: function () {
  145. return {
  146. message: 'world'
  147. }
  148. }
  149. }
  150. }
  151. })
  152. expect(el.firstChild.style.display).toBe('none')
  153. expect(el.firstChild.textContent).toBe('hello world')
  154. vm.ok = true
  155. vm.message = 'bye'
  156. _.nextTick(function () {
  157. expect(el.firstChild.style.display).toBe('')
  158. expect(el.firstChild.textContent).toBe('bye world')
  159. done()
  160. })
  161. })
  162. it('parent content + v-if', function (done) {
  163. var vm = new Vue({
  164. el: el,
  165. data: {
  166. ok: false,
  167. message: 'hello'
  168. },
  169. template: '<div v-component="test" v-if="ok">{{message}}</div>',
  170. components: {
  171. test: {
  172. template: '<content></content> {{message}}',
  173. data: function () {
  174. return {
  175. message: 'world'
  176. }
  177. }
  178. }
  179. }
  180. })
  181. expect(el.textContent).toBe('')
  182. expect(vm._children).toBeNull()
  183. expect(vm._directives.length).toBe(1) // v-if
  184. vm.ok = true
  185. _.nextTick(function () {
  186. expect(vm._children.length).toBe(1)
  187. expect(vm._directives.length).toBe(3) // v-if, v-component, v-text
  188. expect(el.textContent).toBe('hello world')
  189. done()
  190. })
  191. })
  192. it('wait-for', function (done) {
  193. var vm = new Vue({
  194. el: el,
  195. data: {
  196. view: 'a'
  197. },
  198. template: '<div v-component="{{view}}" wait-for="ok"></div>',
  199. components: {
  200. a: {
  201. template: 'AAA'
  202. },
  203. b: {
  204. template: 'BBB'
  205. }
  206. }
  207. })
  208. vm._children[0].$emit('ok')
  209. vm.view = 'b'
  210. _.nextTick(function () {
  211. expect(el.textContent).toBe('AAA')
  212. // old vm is already removed, this is the new vm
  213. vm._children[0].$emit('ok')
  214. expect(el.textContent).toBe('BBB')
  215. done()
  216. })
  217. })
  218. it('transition-mode: in-out', function (done) {
  219. var spy1 = jasmine.createSpy('enter')
  220. var spy2 = jasmine.createSpy('leave')
  221. var next
  222. // === IMPORTANT ===
  223. // PhantomJS always returns false when calling
  224. // Element.contains() on a comment node. This causes
  225. // transitions to be skipped. Monkey patching here
  226. // isn't ideal but does the job...
  227. var inDoc = _.inDoc
  228. _.inDoc = function () {
  229. return true
  230. }
  231. var vm = new Vue({
  232. el: el,
  233. data: {
  234. view: 'a'
  235. },
  236. template: '<div v-component="{{view}}" v-transition="test" transition-mode="in-out"></div>',
  237. components: {
  238. a: { template: 'AAA' },
  239. b: { template: 'BBB' }
  240. },
  241. transitions: {
  242. test: {
  243. enter: function (el, done) {
  244. spy1()
  245. next = done
  246. },
  247. leave: function (el, done) {
  248. spy2()
  249. done()
  250. }
  251. }
  252. }
  253. })
  254. expect(el.textContent).toBe('AAA')
  255. vm.view = 'b'
  256. _.nextTick(function () {
  257. expect(spy1).toHaveBeenCalled()
  258. expect(spy2).not.toHaveBeenCalled()
  259. expect(el.textContent).toBe('AAABBB')
  260. next()
  261. expect(spy2).toHaveBeenCalled()
  262. expect(el.textContent).toBe('BBB')
  263. // clean up
  264. _.inDoc = inDoc
  265. done()
  266. })
  267. })
  268. it('transition-mode: out-in', function (done) {
  269. var spy1 = jasmine.createSpy('enter')
  270. var spy2 = jasmine.createSpy('leave')
  271. var next
  272. var inDoc = _.inDoc
  273. _.inDoc = function () {
  274. return true
  275. }
  276. var vm = new Vue({
  277. el: el,
  278. data: {
  279. view: 'a'
  280. },
  281. template: '<div v-component="{{view}}" v-transition="test" transition-mode="out-in"></div>',
  282. components: {
  283. a: { template: 'AAA' },
  284. b: { template: 'BBB' }
  285. },
  286. transitions: {
  287. test: {
  288. enter: function (el, done) {
  289. spy2()
  290. done()
  291. },
  292. leave: function (el, done) {
  293. spy1()
  294. next = done
  295. }
  296. }
  297. }
  298. })
  299. expect(el.textContent).toBe('AAA')
  300. vm.view = 'b'
  301. _.nextTick(function () {
  302. expect(spy1).toHaveBeenCalled()
  303. expect(spy2).not.toHaveBeenCalled()
  304. expect(el.textContent).toBe('AAA')
  305. next()
  306. expect(spy2).toHaveBeenCalled()
  307. expect(el.textContent).toBe('BBB')
  308. // clean up
  309. _.inDoc = inDoc
  310. done()
  311. })
  312. })
  313. it('teardown', function (done) {
  314. var vm = new Vue({
  315. el: el,
  316. template: '<div v-component="{{view}}" keep-alive></div>',
  317. data: {
  318. view: 'test'
  319. },
  320. components: {
  321. test: {},
  322. test2: {}
  323. }
  324. })
  325. vm.view = 'test2'
  326. _.nextTick(function () {
  327. expect(vm._children.length).toBe(2)
  328. var child = vm._children[0]
  329. var child2 = vm._children[1]
  330. vm._directives[0].unbind()
  331. expect(vm._directives[0].cache).toBeNull()
  332. expect(vm._children.length).toBe(0)
  333. expect(child._isDestroyed).toBe(true)
  334. expect(child2._isDestroyed).toBe(true)
  335. done()
  336. })
  337. })
  338. it('already mounted warn', function () {
  339. el.setAttribute('v-component', 'test')
  340. var vm = new Vue({
  341. el: el
  342. })
  343. expect(_.warn).toHaveBeenCalled()
  344. })
  345. })
  346. }