if_spec.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. var _ = require('../../../../src/util')
  2. var Vue = require('../../../../src/vue')
  3. if (_.inBrowser) {
  4. describe('v-if', function () {
  5. var el
  6. beforeEach(function () {
  7. el = document.createElement('div')
  8. spyOn(_, 'warn')
  9. })
  10. it('normal', function (done) {
  11. var vm = new Vue({
  12. el: el,
  13. data: { test: false, a: 'A' },
  14. template: '<div v-if="test"><test></test></div>',
  15. components: {
  16. test: {
  17. inherit: true,
  18. template: '{{a}}'
  19. }
  20. }
  21. })
  22. // lazy instantitation
  23. expect(el.innerHTML).toBe('')
  24. expect(vm.$children.length).toBe(0)
  25. vm.test = true
  26. _.nextTick(function () {
  27. expect(el.innerHTML).toBe('<div><test>A</test></div>')
  28. expect(vm.$children.length).toBe(1)
  29. vm.test = false
  30. _.nextTick(function () {
  31. expect(el.innerHTML).toBe('')
  32. expect(vm.$children.length).toBe(0)
  33. vm.test = true
  34. _.nextTick(function () {
  35. expect(el.innerHTML).toBe('<div><test>A</test></div>')
  36. expect(vm.$children.length).toBe(1)
  37. var child = vm.$children[0]
  38. vm.$destroy()
  39. expect(child._isDestroyed).toBe(true)
  40. done()
  41. })
  42. })
  43. })
  44. })
  45. it('template block', function (done) {
  46. var vm = new Vue({
  47. el: el,
  48. data: { test: false, a: 'A', b: 'B' },
  49. template: '<template v-if="test"><p>{{a}}</p><p>{{b}}</p></template>'
  50. })
  51. // lazy instantitation
  52. expect(el.innerHTML).toBe('')
  53. vm.test = true
  54. _.nextTick(function () {
  55. expect(el.innerHTML).toBe('<p>A</p><p>B</p>')
  56. vm.test = false
  57. _.nextTick(function () {
  58. expect(el.innerHTML).toBe('')
  59. done()
  60. })
  61. })
  62. })
  63. it('v-if + v-component', function (done) {
  64. var attachSpy = jasmine.createSpy()
  65. var detachSpy = jasmine.createSpy()
  66. var readySpy = jasmine.createSpy()
  67. var vm = new Vue({
  68. el: el,
  69. data: { ok: false },
  70. template: '<test v-if="ok"></test>',
  71. components: {
  72. test: {
  73. data: function () {
  74. return { a: 123 }
  75. },
  76. template: '{{a}}',
  77. ready: readySpy,
  78. attached: attachSpy,
  79. detached: detachSpy
  80. }
  81. }
  82. })
  83. vm.$appendTo(document.body)
  84. expect(el.innerHTML).toBe('')
  85. expect(vm.$children.length).toBe(0)
  86. vm.ok = true
  87. _.nextTick(function () {
  88. expect(el.innerHTML).toBe('<test>123</test>')
  89. expect(vm.$children.length).toBe(1)
  90. expect(attachSpy).toHaveBeenCalled()
  91. expect(readySpy).toHaveBeenCalled()
  92. vm.ok = false
  93. _.nextTick(function () {
  94. expect(detachSpy).toHaveBeenCalled()
  95. expect(el.innerHTML).toBe('')
  96. expect(vm.$children.length).toBe(0)
  97. vm.$remove()
  98. done()
  99. })
  100. })
  101. })
  102. it('v-if + dynamic component', function (done) {
  103. var vm = new Vue({
  104. el: el,
  105. data: {
  106. ok: false,
  107. view: 'view-a'
  108. },
  109. template: '<component is="{{view}}" v-if="ok"></component>',
  110. components: {
  111. 'view-a': {
  112. template: 'AAA'
  113. },
  114. 'view-b': {
  115. template: 'BBB'
  116. }
  117. }
  118. })
  119. expect(el.innerHTML).toBe('')
  120. expect(vm.$children.length).toBe(0)
  121. // toggle if with lazy instantiation
  122. vm.ok = true
  123. _.nextTick(function () {
  124. expect(el.innerHTML).toBe('<component>AAA</component>')
  125. expect(vm.$children.length).toBe(1)
  126. // switch view when if=true
  127. vm.view = 'view-b'
  128. _.nextTick(function () {
  129. expect(el.innerHTML).toBe('<component>BBB</component>')
  130. expect(vm.$children.length).toBe(1)
  131. // toggle if when already instantiated
  132. vm.ok = false
  133. _.nextTick(function () {
  134. expect(el.innerHTML).toBe('')
  135. expect(vm.$children.length).toBe(0)
  136. // toggle if and switch view at the same time
  137. vm.view = 'view-a'
  138. vm.ok = true
  139. _.nextTick(function () {
  140. expect(el.innerHTML).toBe('<component>AAA</component>')
  141. expect(vm.$children.length).toBe(1)
  142. done()
  143. })
  144. })
  145. })
  146. })
  147. })
  148. it('v-if with different truthy values', function (done) {
  149. var vm = new Vue({
  150. el: el,
  151. data: {
  152. a: 1
  153. },
  154. template: '<div v-if="a">{{a}}</div>'
  155. })
  156. expect(el.innerHTML).toBe('<div>1</div>')
  157. vm.a = 2
  158. _.nextTick(function () {
  159. expect(el.innerHTML).toBe('<div>2</div>')
  160. done()
  161. })
  162. })
  163. it('invalid warn', function () {
  164. el.setAttribute('v-if', 'test')
  165. new Vue({
  166. el: el
  167. })
  168. expect(hasWarned(_, 'cannot be used on an instance root element')).toBe(true)
  169. })
  170. it('call attach/detach for transcluded components', function (done) {
  171. document.body.appendChild(el)
  172. var attachSpy = jasmine.createSpy('attached')
  173. var detachSpy = jasmine.createSpy('detached')
  174. var vm = new Vue({
  175. el: el,
  176. data: { show: true },
  177. template: '<outer><transcluded></transcluded></outer>',
  178. components: {
  179. outer: {
  180. template: '<div v-if="$parent.show"><content></content></div>'
  181. },
  182. transcluded: {
  183. template: 'transcluded',
  184. attached: attachSpy,
  185. detached: detachSpy
  186. }
  187. }
  188. })
  189. expect(attachSpy).toHaveBeenCalled()
  190. vm.show = false
  191. _.nextTick(function () {
  192. expect(detachSpy).toHaveBeenCalled()
  193. document.body.removeChild(el)
  194. done()
  195. })
  196. })
  197. it('call attach/detach for dynamicly created components inside if block', function (done) {
  198. document.body.appendChild(el)
  199. var attachSpy = jasmine.createSpy('attached')
  200. var detachSpy = jasmine.createSpy('detached')
  201. var vm = new Vue({
  202. el: el,
  203. data: {
  204. show: true,
  205. list: [{a: 0}]
  206. },
  207. template:
  208. '<outer>' +
  209. '<div>' + // an extra layer to test components deep inside the tree
  210. '<transcluded v-repeat="list"></transcluded>' +
  211. '</div>' +
  212. '</outer>',
  213. components: {
  214. outer: {
  215. template:
  216. '<div v-if="$parent.show">' +
  217. '<content></content>' +
  218. '</div>' +
  219. // this is to test that compnents that are not in the if block
  220. // should not fire attach/detach when v-if toggles
  221. '<transcluded></transcluded>'
  222. },
  223. transcluded: {
  224. template: '{{a}}',
  225. attached: attachSpy,
  226. detached: detachSpy
  227. }
  228. }
  229. })
  230. assertMarkup()
  231. expect(attachSpy.calls.count()).toBe(2)
  232. vm.show = false
  233. _.nextTick(function () {
  234. assertMarkup()
  235. expect(detachSpy.calls.count()).toBe(1)
  236. vm.list.push({a: 1})
  237. vm.show = true
  238. _.nextTick(function () {
  239. assertMarkup()
  240. expect(attachSpy.calls.count()).toBe(2 + 2)
  241. vm.list.push({a: 2})
  242. vm.show = false
  243. _.nextTick(function () {
  244. assertMarkup()
  245. expect(attachSpy.calls.count()).toBe(2 + 2 + 1)
  246. expect(detachSpy.calls.count()).toBe(1 + 3)
  247. document.body.removeChild(el)
  248. done()
  249. })
  250. })
  251. })
  252. function assertMarkup () {
  253. var showBlock = vm.show
  254. ? '<div><div>' +
  255. vm.list.map(function (o) {
  256. return '<transcluded>' + o.a + '</transcluded>'
  257. }).join('') +
  258. '</div></div>'
  259. : ''
  260. var markup =
  261. '<outer>' +
  262. showBlock +
  263. '<transcluded></transcluded>' +
  264. '</outer>'
  265. expect(el.innerHTML).toBe(markup)
  266. }
  267. })
  268. // #893 in IE textNodes do not have `contains` method
  269. it('call attach/detach: comparing textNodes in IE', function (done) {
  270. document.body.appendChild(el)
  271. var attachSpy = jasmine.createSpy('attached')
  272. var detachSpy = jasmine.createSpy('detached')
  273. var vm = new Vue({
  274. el: el,
  275. data: {
  276. show: true
  277. },
  278. template: '<template v-if="show"><test></test></template>',
  279. components: {
  280. test: {
  281. template: 'hi',
  282. replace: true,
  283. attached: attachSpy,
  284. detached: detachSpy
  285. }
  286. }
  287. })
  288. assertMarkup()
  289. assertCalls(1, 0)
  290. vm.show = false
  291. _.nextTick(function () {
  292. assertMarkup()
  293. assertCalls(1, 1)
  294. vm.show = true
  295. _.nextTick(function () {
  296. assertMarkup()
  297. assertCalls(2, 1)
  298. vm.show = false
  299. _.nextTick(function () {
  300. assertMarkup()
  301. assertCalls(2, 2)
  302. document.body.removeChild(el)
  303. done()
  304. })
  305. })
  306. })
  307. function assertMarkup () {
  308. expect(el.innerHTML).toBe(vm.show ? 'hi' : '')
  309. }
  310. function assertCalls (attach, detach) {
  311. expect(attachSpy.calls.count()).toBe(attach)
  312. expect(detachSpy.calls.count()).toBe(detach)
  313. }
  314. })
  315. // #1097 v-if components not having correct parent
  316. it('compile with correct transclusion host', function () {
  317. var parentA
  318. var parentB
  319. new Vue({
  320. el: el,
  321. data: {
  322. show: true
  323. },
  324. template: '<parent><child v-if="show"></child></parent>',
  325. components: {
  326. parent: {
  327. template: '<content></content>',
  328. created: function () {
  329. parentA = this
  330. }
  331. },
  332. child: {
  333. created: function () {
  334. parentB = this.$parent
  335. }
  336. }
  337. }
  338. })
  339. expect(parentA).toBeTruthy()
  340. expect(parentA).toBe(parentB)
  341. })
  342. })
  343. }