component_spec.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. vm._children[1].$emit('ok')
  213. expect(el.textContent).toBe('BBB')
  214. done()
  215. })
  216. })
  217. it('transition-mode: in-out', function (done) {
  218. var spy1 = jasmine.createSpy('enter')
  219. var spy2 = jasmine.createSpy('leave')
  220. var next
  221. // === IMPORTANT ===
  222. // PhantomJS always returns false when calling
  223. // Element.contains() on a comment node. This causes
  224. // transitions to be skipped. Monkey patching here
  225. // isn't ideal but does the job...
  226. var inDoc = _.inDoc
  227. _.inDoc = function () {
  228. return true
  229. }
  230. var vm = new Vue({
  231. el: el,
  232. data: {
  233. view: 'a'
  234. },
  235. template: '<div v-component="{{view}}" v-transition="test" transition-mode="in-out"></div>',
  236. components: {
  237. a: { template: 'AAA' },
  238. b: { template: 'BBB' }
  239. },
  240. transitions: {
  241. test: {
  242. enter: function (el, done) {
  243. spy1()
  244. next = done
  245. },
  246. leave: function (el, done) {
  247. spy2()
  248. done()
  249. }
  250. }
  251. }
  252. })
  253. expect(el.textContent).toBe('AAA')
  254. vm.view = 'b'
  255. _.nextTick(function () {
  256. expect(spy1).toHaveBeenCalled()
  257. expect(spy2).not.toHaveBeenCalled()
  258. expect(el.textContent).toBe('AAABBB')
  259. next()
  260. expect(spy2).toHaveBeenCalled()
  261. expect(el.textContent).toBe('BBB')
  262. // clean up
  263. _.inDoc = inDoc
  264. done()
  265. })
  266. })
  267. it('transition-mode: out-in', function (done) {
  268. var spy1 = jasmine.createSpy('enter')
  269. var spy2 = jasmine.createSpy('leave')
  270. var next
  271. var inDoc = _.inDoc
  272. _.inDoc = function () {
  273. return true
  274. }
  275. var vm = new Vue({
  276. el: el,
  277. data: {
  278. view: 'a'
  279. },
  280. template: '<div v-component="{{view}}" v-transition="test" transition-mode="out-in"></div>',
  281. components: {
  282. a: { template: 'AAA' },
  283. b: { template: 'BBB' }
  284. },
  285. transitions: {
  286. test: {
  287. enter: function (el, done) {
  288. spy2()
  289. done()
  290. },
  291. leave: function (el, done) {
  292. spy1()
  293. next = done
  294. }
  295. }
  296. }
  297. })
  298. expect(el.textContent).toBe('AAA')
  299. vm.view = 'b'
  300. _.nextTick(function () {
  301. expect(spy1).toHaveBeenCalled()
  302. expect(spy2).not.toHaveBeenCalled()
  303. expect(el.textContent).toBe('AAA')
  304. next()
  305. expect(spy2).toHaveBeenCalled()
  306. expect(el.textContent).toBe('BBB')
  307. // clean up
  308. _.inDoc = inDoc
  309. done()
  310. })
  311. })
  312. it('teardown', function (done) {
  313. var vm = new Vue({
  314. el: el,
  315. template: '<div v-component="{{view}}" keep-alive></div>',
  316. data: {
  317. view: 'test'
  318. },
  319. components: {
  320. test: {},
  321. test2: {}
  322. }
  323. })
  324. vm.view = 'test2'
  325. _.nextTick(function () {
  326. expect(vm._children.length).toBe(2)
  327. var child = vm._children[0]
  328. var child2 = vm._children[1]
  329. vm._directives[0].unbind()
  330. expect(vm._directives[0].cache).toBeNull()
  331. expect(vm._children.length).toBe(0)
  332. expect(child._isDestroyed).toBe(true)
  333. expect(child2._isDestroyed).toBe(true)
  334. done()
  335. })
  336. })
  337. it('already mounted warn', function () {
  338. el.setAttribute('v-component', 'test')
  339. var vm = new Vue({
  340. el: el
  341. })
  342. expect(_.warn).toHaveBeenCalled()
  343. })
  344. })
  345. }