component_spec.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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: '<div><content></content> {{message}}</div>',
  144. replace: true,
  145. data: function () {
  146. return {
  147. message: 'world'
  148. }
  149. }
  150. }
  151. }
  152. })
  153. expect(el.firstChild.style.display).toBe('none')
  154. expect(el.firstChild.textContent).toBe('hello world')
  155. vm.ok = true
  156. vm.message = 'bye'
  157. _.nextTick(function () {
  158. expect(el.firstChild.style.display).toBe('')
  159. expect(el.firstChild.textContent).toBe('bye world')
  160. done()
  161. })
  162. })
  163. it('parent content + v-if', function (done) {
  164. var vm = new Vue({
  165. el: el,
  166. data: {
  167. ok: false,
  168. message: 'hello'
  169. },
  170. template: '<div v-component="test" v-if="ok">{{message}}</div>',
  171. components: {
  172. test: {
  173. template: '<content></content> {{message}}',
  174. data: function () {
  175. return {
  176. message: 'world'
  177. }
  178. }
  179. }
  180. }
  181. })
  182. expect(el.textContent).toBe('')
  183. expect(vm._children).toBeNull()
  184. expect(vm._directives.length).toBe(1) // v-if
  185. vm.ok = true
  186. _.nextTick(function () {
  187. expect(vm._children.length).toBe(1)
  188. expect(vm._directives.length).toBe(3) // v-if, v-component, v-text
  189. expect(el.textContent).toBe('hello world')
  190. done()
  191. })
  192. })
  193. it('paramAttributes', function () {
  194. var vm = new Vue({
  195. el: el,
  196. data: {
  197. list: [{a:1}, {a:2}]
  198. },
  199. template: '<ul v-component="test" collection="{{list}}"></ul>',
  200. components: {
  201. test: {
  202. template: '<li v-repeat="collection">{{a}}</li>',
  203. paramAttributes: ['collection']
  204. }
  205. }
  206. })
  207. expect(el.innerHTML).toBe('<ul><li>1</li><li>2</li><!--v-repeat--></ul><!--v-component-->')
  208. })
  209. it('wait-for', function (done) {
  210. var vm = new Vue({
  211. el: el,
  212. data: {
  213. view: 'a'
  214. },
  215. template: '<div v-component="{{view}}" wait-for="ok"></div>',
  216. components: {
  217. a: {
  218. template: 'AAA'
  219. },
  220. b: {
  221. template: 'BBB'
  222. }
  223. }
  224. })
  225. vm._children[0].$emit('ok')
  226. vm.view = 'b'
  227. _.nextTick(function () {
  228. expect(el.textContent).toBe('AAA')
  229. // old vm is already removed, this is the new vm
  230. vm._children[0].$emit('ok')
  231. expect(el.textContent).toBe('BBB')
  232. done()
  233. })
  234. })
  235. it('transition-mode: in-out', function (done) {
  236. var spy1 = jasmine.createSpy('enter')
  237. var spy2 = jasmine.createSpy('leave')
  238. var next
  239. // === IMPORTANT ===
  240. // PhantomJS always returns false when calling
  241. // Element.contains() on a comment node. This causes
  242. // transitions to be skipped. Monkey patching here
  243. // isn't ideal but does the job...
  244. var inDoc = _.inDoc
  245. _.inDoc = function () {
  246. return true
  247. }
  248. var vm = new Vue({
  249. el: el,
  250. data: {
  251. view: 'a'
  252. },
  253. template: '<div v-component="{{view}}" v-transition="test" transition-mode="in-out"></div>',
  254. components: {
  255. a: { template: 'AAA' },
  256. b: { template: 'BBB' }
  257. },
  258. transitions: {
  259. test: {
  260. enter: function (el, done) {
  261. spy1()
  262. next = done
  263. },
  264. leave: function (el, done) {
  265. spy2()
  266. done()
  267. }
  268. }
  269. }
  270. })
  271. expect(el.textContent).toBe('AAA')
  272. vm.view = 'b'
  273. _.nextTick(function () {
  274. expect(spy1).toHaveBeenCalled()
  275. expect(spy2).not.toHaveBeenCalled()
  276. expect(el.textContent).toBe('AAABBB')
  277. next()
  278. expect(spy2).toHaveBeenCalled()
  279. expect(el.textContent).toBe('BBB')
  280. // clean up
  281. _.inDoc = inDoc
  282. done()
  283. })
  284. })
  285. it('transition-mode: out-in', function (done) {
  286. var spy1 = jasmine.createSpy('enter')
  287. var spy2 = jasmine.createSpy('leave')
  288. var next
  289. var inDoc = _.inDoc
  290. _.inDoc = function () {
  291. return true
  292. }
  293. var vm = new Vue({
  294. el: el,
  295. data: {
  296. view: 'a'
  297. },
  298. template: '<div v-component="{{view}}" v-transition="test" transition-mode="out-in"></div>',
  299. components: {
  300. a: { template: 'AAA' },
  301. b: { template: 'BBB' }
  302. },
  303. transitions: {
  304. test: {
  305. enter: function (el, done) {
  306. spy2()
  307. done()
  308. },
  309. leave: function (el, done) {
  310. spy1()
  311. next = done
  312. }
  313. }
  314. }
  315. })
  316. expect(el.textContent).toBe('AAA')
  317. vm.view = 'b'
  318. _.nextTick(function () {
  319. expect(spy1).toHaveBeenCalled()
  320. expect(spy2).not.toHaveBeenCalled()
  321. expect(el.textContent).toBe('AAA')
  322. next()
  323. expect(spy2).toHaveBeenCalled()
  324. expect(el.textContent).toBe('BBB')
  325. // clean up
  326. _.inDoc = inDoc
  327. done()
  328. })
  329. })
  330. it('teardown', function (done) {
  331. var vm = new Vue({
  332. el: el,
  333. template: '<div v-component="{{view}}" keep-alive></div>',
  334. data: {
  335. view: 'test'
  336. },
  337. components: {
  338. test: {},
  339. test2: {}
  340. }
  341. })
  342. vm.view = 'test2'
  343. _.nextTick(function () {
  344. expect(vm._children.length).toBe(2)
  345. var child = vm._children[0]
  346. var child2 = vm._children[1]
  347. vm._directives[0].unbind()
  348. expect(vm._directives[0].cache).toBeNull()
  349. expect(vm._children.length).toBe(0)
  350. expect(child._isDestroyed).toBe(true)
  351. expect(child2._isDestroyed).toBe(true)
  352. done()
  353. })
  354. })
  355. it('already mounted warn', function () {
  356. el.setAttribute('v-component', 'test')
  357. var vm = new Vue({
  358. el: el
  359. })
  360. expect(_.warn).toHaveBeenCalled()
  361. })
  362. })
  363. }