transition.spec.js 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  1. import Vue from 'vue'
  2. import injectStyles from './inject-styles'
  3. import { isIE9 } from 'core/util/env'
  4. import { nextFrame } from 'web/runtime/transition-util'
  5. if (!isIE9) {
  6. describe('Transition basic', () => {
  7. const { duration, buffer } = injectStyles()
  8. const explicitDuration = duration * 2
  9. let el
  10. beforeEach(() => {
  11. el = document.createElement('div')
  12. document.body.appendChild(el)
  13. })
  14. it('basic transition', done => {
  15. const vm = new Vue({
  16. template: '<div><transition><div v-if="ok" class="test">foo</div></transition></div>',
  17. data: { ok: true }
  18. }).$mount(el)
  19. // should not apply transition on initial render by default
  20. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  21. vm.ok = false
  22. waitForUpdate(() => {
  23. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  24. }).thenWaitFor(nextFrame).then(() => {
  25. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  26. }).thenWaitFor(duration + buffer).then(() => {
  27. expect(vm.$el.children.length).toBe(0)
  28. vm.ok = true
  29. }).then(() => {
  30. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  31. }).thenWaitFor(nextFrame).then(() => {
  32. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  33. }).thenWaitFor(duration + buffer).then(() => {
  34. expect(vm.$el.children[0].className).toBe('test')
  35. }).then(done)
  36. })
  37. it('named transition', done => {
  38. const vm = new Vue({
  39. template: '<div><transition name="test"><div v-if="ok" class="test">foo</div></transition></div>',
  40. data: { ok: true }
  41. }).$mount(el)
  42. // should not apply transition on initial render by default
  43. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  44. vm.ok = false
  45. waitForUpdate(() => {
  46. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  47. }).thenWaitFor(nextFrame).then(() => {
  48. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  49. }).thenWaitFor(duration + buffer).then(() => {
  50. expect(vm.$el.children.length).toBe(0)
  51. vm.ok = true
  52. }).then(() => {
  53. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  54. }).thenWaitFor(nextFrame).then(() => {
  55. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  56. }).thenWaitFor(duration + buffer).then(() => {
  57. expect(vm.$el.children[0].className).toBe('test')
  58. }).then(done)
  59. })
  60. it('custom transition classes', done => {
  61. const vm = new Vue({
  62. template: `
  63. <div>
  64. <transition
  65. enter-class="hello"
  66. enter-active-class="hello-active"
  67. enter-to-class="hello-to"
  68. leave-class="bye"
  69. leave-to-class="bye-to"
  70. leave-active-class="byebye active more ">
  71. <div v-if="ok" class="test">foo</div>
  72. </transition>
  73. </div>
  74. `,
  75. data: { ok: true }
  76. }).$mount(el)
  77. // should not apply transition on initial render by default
  78. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  79. vm.ok = false
  80. waitForUpdate(() => {
  81. expect(vm.$el.children[0].className).toBe('test bye byebye active more')
  82. }).thenWaitFor(nextFrame).then(() => {
  83. expect(vm.$el.children[0].className).toBe('test byebye active more bye-to')
  84. }).thenWaitFor(duration + buffer).then(() => {
  85. expect(vm.$el.children.length).toBe(0)
  86. vm.ok = true
  87. }).then(() => {
  88. expect(vm.$el.children[0].className).toBe('test hello hello-active')
  89. }).thenWaitFor(nextFrame).then(() => {
  90. expect(vm.$el.children[0].className).toBe('test hello-active hello-to')
  91. }).thenWaitFor(duration + buffer).then(() => {
  92. expect(vm.$el.children[0].className).toBe('test')
  93. }).then(done)
  94. })
  95. it('dynamic transition', done => {
  96. const vm = new Vue({
  97. template: `
  98. <div>
  99. <transition :name="trans">
  100. <div v-if="ok" class="test">foo</div>
  101. </transition>
  102. </div>
  103. `,
  104. data: {
  105. ok: true,
  106. trans: 'test'
  107. }
  108. }).$mount(el)
  109. // should not apply transition on initial render by default
  110. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  111. vm.ok = false
  112. waitForUpdate(() => {
  113. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  114. }).thenWaitFor(nextFrame).then(() => {
  115. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  116. }).thenWaitFor(duration + buffer).then(() => {
  117. expect(vm.$el.children.length).toBe(0)
  118. vm.ok = true
  119. vm.trans = 'changed'
  120. }).then(() => {
  121. expect(vm.$el.children[0].className).toBe('test changed-enter changed-enter-active')
  122. }).thenWaitFor(nextFrame).then(() => {
  123. expect(vm.$el.children[0].className).toBe('test changed-enter-active changed-enter-to')
  124. }).thenWaitFor(duration + buffer).then(() => {
  125. expect(vm.$el.children[0].className).toBe('test')
  126. }).then(done)
  127. })
  128. it('inline transition object', done => {
  129. const enter = jasmine.createSpy('enter')
  130. const leave = jasmine.createSpy('leave')
  131. const vm = new Vue({
  132. render (h) {
  133. return h('div', null, [
  134. h('transition', {
  135. props: {
  136. name: 'inline',
  137. enterClass: 'hello',
  138. enterToClass: 'hello-to',
  139. enterActiveClass: 'hello-active',
  140. leaveClass: 'bye',
  141. leaveToClass: 'bye-to',
  142. leaveActiveClass: 'byebye active'
  143. },
  144. on: {
  145. enter,
  146. leave
  147. }
  148. }, this.ok ? [h('div', { class: 'test' }, 'foo')] : undefined)
  149. ])
  150. },
  151. data: { ok: true }
  152. }).$mount(el)
  153. // should not apply transition on initial render by default
  154. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  155. vm.ok = false
  156. waitForUpdate(() => {
  157. expect(vm.$el.children[0].className).toBe('test bye byebye active')
  158. expect(leave).toHaveBeenCalled()
  159. }).thenWaitFor(nextFrame).then(() => {
  160. expect(vm.$el.children[0].className).toBe('test byebye active bye-to')
  161. }).thenWaitFor(duration + buffer).then(() => {
  162. expect(vm.$el.children.length).toBe(0)
  163. vm.ok = true
  164. }).then(() => {
  165. expect(vm.$el.children[0].className).toBe('test hello hello-active')
  166. expect(enter).toHaveBeenCalled()
  167. }).thenWaitFor(nextFrame).then(() => {
  168. expect(vm.$el.children[0].className).toBe('test hello-active hello-to')
  169. }).thenWaitFor(duration + buffer).then(() => {
  170. expect(vm.$el.children[0].className).toBe('test')
  171. }).then(done)
  172. })
  173. it('transition events', done => {
  174. const onLeaveSpy = jasmine.createSpy('leave')
  175. const onEnterSpy = jasmine.createSpy('enter')
  176. const beforeLeaveSpy = jasmine.createSpy('beforeLeave')
  177. const beforeEnterSpy = jasmine.createSpy('beforeEnter')
  178. const afterLeaveSpy = jasmine.createSpy('afterLeave')
  179. const afterEnterSpy = jasmine.createSpy('afterEnter')
  180. const vm = new Vue({
  181. template: `
  182. <div>
  183. <transition
  184. name="test"
  185. @before-enter="beforeEnter"
  186. @enter="enter"
  187. @after-enter="afterEnter"
  188. @before-leave="beforeLeave"
  189. @leave="leave"
  190. @after-leave="afterLeave">
  191. <div v-if="ok" class="test">foo</div>
  192. </transition>
  193. </div>
  194. `,
  195. data: { ok: true },
  196. methods: {
  197. beforeLeave: (el) => {
  198. expect(el).toBe(vm.$el.children[0])
  199. expect(el.className).toBe('test')
  200. beforeLeaveSpy(el)
  201. },
  202. leave: (el) => onLeaveSpy(el),
  203. afterLeave: (el) => afterLeaveSpy(el),
  204. beforeEnter: (el) => {
  205. expect(vm.$el.contains(el)).toBe(false)
  206. expect(el.className).toBe('test')
  207. beforeEnterSpy(el)
  208. },
  209. enter: (el) => {
  210. expect(vm.$el.contains(el)).toBe(true)
  211. onEnterSpy(el)
  212. },
  213. afterEnter: (el) => afterEnterSpy(el)
  214. }
  215. }).$mount(el)
  216. // should not apply transition on initial render by default
  217. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  218. let _el = vm.$el.children[0]
  219. vm.ok = false
  220. waitForUpdate(() => {
  221. expect(beforeLeaveSpy).toHaveBeenCalledWith(_el)
  222. expect(onLeaveSpy).toHaveBeenCalledWith(_el)
  223. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  224. }).thenWaitFor(nextFrame).then(() => {
  225. expect(afterLeaveSpy).not.toHaveBeenCalled()
  226. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  227. }).thenWaitFor(duration + buffer).then(() => {
  228. expect(afterLeaveSpy).toHaveBeenCalledWith(_el)
  229. expect(vm.$el.children.length).toBe(0)
  230. vm.ok = true
  231. }).then(() => {
  232. _el = vm.$el.children[0]
  233. expect(beforeEnterSpy).toHaveBeenCalledWith(_el)
  234. expect(onEnterSpy).toHaveBeenCalledWith(_el)
  235. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  236. }).thenWaitFor(nextFrame).then(() => {
  237. expect(afterEnterSpy).not.toHaveBeenCalled()
  238. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  239. }).thenWaitFor(duration + buffer).then(() => {
  240. expect(afterEnterSpy).toHaveBeenCalledWith(_el)
  241. expect(vm.$el.children[0].className).toBe('test')
  242. }).then(done)
  243. })
  244. it('transition events (v-show)', done => {
  245. const onLeaveSpy = jasmine.createSpy('leave')
  246. const onEnterSpy = jasmine.createSpy('enter')
  247. const beforeLeaveSpy = jasmine.createSpy('beforeLeave')
  248. const beforeEnterSpy = jasmine.createSpy('beforeEnter')
  249. const afterLeaveSpy = jasmine.createSpy('afterLeave')
  250. const afterEnterSpy = jasmine.createSpy('afterEnter')
  251. const vm = new Vue({
  252. template: `
  253. <div>
  254. <transition
  255. name="test"
  256. @before-enter="beforeEnter"
  257. @enter="enter"
  258. @after-enter="afterEnter"
  259. @before-leave="beforeLeave"
  260. @leave="leave"
  261. @after-leave="afterLeave">
  262. <div v-show="ok" class="test">foo</div>
  263. </transition>
  264. </div>
  265. `,
  266. data: { ok: true },
  267. methods: {
  268. beforeLeave: (el) => {
  269. expect(el.style.display).toBe('')
  270. expect(el).toBe(vm.$el.children[0])
  271. expect(el.className).toBe('test')
  272. beforeLeaveSpy(el)
  273. },
  274. leave: (el) => {
  275. expect(el.style.display).toBe('')
  276. onLeaveSpy(el)
  277. },
  278. afterLeave: (el) => {
  279. expect(el.style.display).toBe('none')
  280. afterLeaveSpy(el)
  281. },
  282. beforeEnter: (el) => {
  283. expect(el.className).toBe('test')
  284. expect(el.style.display).toBe('none')
  285. beforeEnterSpy(el)
  286. },
  287. enter: (el) => {
  288. expect(el.style.display).toBe('')
  289. onEnterSpy(el)
  290. },
  291. afterEnter: (el) => {
  292. expect(el.style.display).toBe('')
  293. afterEnterSpy(el)
  294. }
  295. }
  296. }).$mount(el)
  297. // should not apply transition on initial render by default
  298. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  299. let _el = vm.$el.children[0]
  300. vm.ok = false
  301. waitForUpdate(() => {
  302. expect(beforeLeaveSpy).toHaveBeenCalledWith(_el)
  303. expect(onLeaveSpy).toHaveBeenCalledWith(_el)
  304. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  305. }).thenWaitFor(nextFrame).then(() => {
  306. expect(afterLeaveSpy).not.toHaveBeenCalled()
  307. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  308. }).thenWaitFor(duration + buffer).then(() => {
  309. expect(afterLeaveSpy).toHaveBeenCalledWith(_el)
  310. expect(vm.$el.children[0].style.display).toBe('none')
  311. vm.ok = true
  312. }).then(() => {
  313. _el = vm.$el.children[0]
  314. expect(beforeEnterSpy).toHaveBeenCalledWith(_el)
  315. expect(onEnterSpy).toHaveBeenCalledWith(_el)
  316. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  317. }).thenWaitFor(nextFrame).then(() => {
  318. expect(afterEnterSpy).not.toHaveBeenCalled()
  319. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  320. }).thenWaitFor(duration + buffer).then(() => {
  321. expect(afterEnterSpy).toHaveBeenCalledWith(_el)
  322. expect(vm.$el.children[0].className).toBe('test')
  323. }).then(done)
  324. })
  325. it('explicit user callback in JavaScript hooks', done => {
  326. let next
  327. const vm = new Vue({
  328. template: `<div>
  329. <transition name="test" @enter="enter" @leave="leave">
  330. <div v-if="ok" class="test">foo</div>
  331. </transition>
  332. </div>`,
  333. data: { ok: true },
  334. methods: {
  335. enter: (el, cb) => {
  336. next = cb
  337. },
  338. leave: (el, cb) => {
  339. next = cb
  340. }
  341. }
  342. }).$mount(el)
  343. vm.ok = false
  344. waitForUpdate(() => {
  345. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  346. }).thenWaitFor(nextFrame).then(() => {
  347. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  348. }).thenWaitFor(duration + buffer).then(() => {
  349. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  350. expect(next).toBeTruthy()
  351. next()
  352. expect(vm.$el.children.length).toBe(0)
  353. }).then(() => {
  354. vm.ok = true
  355. }).then(() => {
  356. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  357. }).thenWaitFor(nextFrame).then(() => {
  358. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  359. }).thenWaitFor(duration + buffer).then(() => {
  360. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  361. expect(next).toBeTruthy()
  362. next()
  363. expect(vm.$el.children[0].className).toBe('test')
  364. }).then(done)
  365. })
  366. it('css: false', done => {
  367. const enterSpy = jasmine.createSpy('enter')
  368. const leaveSpy = jasmine.createSpy('leave')
  369. const vm = new Vue({
  370. template: `
  371. <div>
  372. <transition :css="false" name="test" @enter="enter" @leave="leave">
  373. <div v-if="ok" class="test">foo</div>
  374. </transition>
  375. </div>
  376. `,
  377. data: { ok: true },
  378. methods: {
  379. enter: enterSpy,
  380. leave: leaveSpy
  381. }
  382. }).$mount(el)
  383. vm.ok = false
  384. waitForUpdate(() => {
  385. expect(leaveSpy).toHaveBeenCalled()
  386. expect(vm.$el.innerHTML).toBe('<!---->')
  387. vm.ok = true
  388. }).then(() => {
  389. expect(enterSpy).toHaveBeenCalled()
  390. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  391. }).then(done)
  392. })
  393. it('no transition detected', done => {
  394. const enterSpy = jasmine.createSpy('enter')
  395. const leaveSpy = jasmine.createSpy('leave')
  396. const vm = new Vue({
  397. template: '<div><transition name="nope" @enter="enter" @leave="leave"><div v-if="ok">foo</div></transition></div>',
  398. data: { ok: true },
  399. methods: {
  400. enter: enterSpy,
  401. leave: leaveSpy
  402. }
  403. }).$mount(el)
  404. vm.ok = false
  405. waitForUpdate(() => {
  406. expect(leaveSpy).toHaveBeenCalled()
  407. expect(vm.$el.innerHTML).toBe('<div class="nope-leave nope-leave-active">foo</div><!---->')
  408. }).thenWaitFor(nextFrame).then(() => {
  409. expect(vm.$el.innerHTML).toBe('<!---->')
  410. vm.ok = true
  411. }).then(() => {
  412. expect(enterSpy).toHaveBeenCalled()
  413. expect(vm.$el.innerHTML).toBe('<div class="nope-enter nope-enter-active">foo</div>')
  414. }).thenWaitFor(nextFrame).then(() => {
  415. expect(vm.$el.innerHTML).toBe('<div>foo</div>')
  416. }).then(done)
  417. })
  418. it('enterCancelled', done => {
  419. const spy = jasmine.createSpy('enterCancelled')
  420. const vm = new Vue({
  421. template: `
  422. <div>
  423. <transition name="test" @enter-cancelled="enterCancelled">
  424. <div v-if="ok" class="test">foo</div>
  425. </transition>
  426. </div>
  427. `,
  428. data: { ok: false },
  429. methods: {
  430. enterCancelled: spy
  431. }
  432. }).$mount(el)
  433. expect(vm.$el.innerHTML).toBe('<!---->')
  434. vm.ok = true
  435. waitForUpdate(() => {
  436. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  437. }).thenWaitFor(nextFrame).then(() => {
  438. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  439. }).thenWaitFor(duration / 2).then(() => {
  440. vm.ok = false
  441. }).then(() => {
  442. expect(spy).toHaveBeenCalled()
  443. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  444. }).thenWaitFor(nextFrame).then(() => {
  445. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  446. }).thenWaitFor(duration + buffer).then(() => {
  447. expect(vm.$el.children.length).toBe(0)
  448. }).then(done)
  449. })
  450. it('should remove stale leaving elements', done => {
  451. const spy = jasmine.createSpy('afterLeave')
  452. const vm = new Vue({
  453. template: `
  454. <div>
  455. <transition name="test" @after-leave="afterLeave">
  456. <div v-if="ok" class="test">foo</div>
  457. </transition>
  458. </div>
  459. `,
  460. data: { ok: true },
  461. methods: {
  462. afterLeave: spy
  463. }
  464. }).$mount(el)
  465. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  466. vm.ok = false
  467. waitForUpdate(() => {
  468. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  469. }).thenWaitFor(duration / 2).then(() => {
  470. vm.ok = true
  471. }).then(() => {
  472. expect(spy).toHaveBeenCalled()
  473. expect(vm.$el.children.length).toBe(1) // should have removed leaving element
  474. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  475. }).thenWaitFor(nextFrame).then(() => {
  476. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  477. }).thenWaitFor(duration + buffer).then(() => {
  478. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  479. }).then(done)
  480. })
  481. it('transition with v-show', done => {
  482. const vm = new Vue({
  483. template: `
  484. <div>
  485. <transition name="test">
  486. <div v-show="ok" class="test">foo</div>
  487. </transition>
  488. </div>
  489. `,
  490. data: { ok: true }
  491. }).$mount(el)
  492. // should not apply transition on initial render by default
  493. expect(vm.$el.textContent).toBe('foo')
  494. expect(vm.$el.children[0].style.display).toBe('')
  495. expect(vm.$el.children[0].className).toBe('test')
  496. vm.ok = false
  497. waitForUpdate(() => {
  498. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  499. }).thenWaitFor(nextFrame).then(() => {
  500. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  501. }).thenWaitFor(duration + buffer).then(() => {
  502. expect(vm.$el.children[0].style.display).toBe('none')
  503. vm.ok = true
  504. }).then(() => {
  505. expect(vm.$el.children[0].style.display).toBe('')
  506. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  507. }).thenWaitFor(nextFrame).then(() => {
  508. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  509. }).thenWaitFor(duration + buffer).then(() => {
  510. expect(vm.$el.children[0].className).toBe('test')
  511. }).then(done)
  512. })
  513. it('transition with v-show, inside child component', done => {
  514. const vm = new Vue({
  515. template: `
  516. <div>
  517. <test v-show="ok"></test>
  518. </div>
  519. `,
  520. data: { ok: true },
  521. components: {
  522. test: {
  523. template: `<transition name="test"><div class="test">foo</div></transition>`
  524. }
  525. }
  526. }).$mount(el)
  527. // should not apply transition on initial render by default
  528. expect(vm.$el.textContent).toBe('foo')
  529. expect(vm.$el.children[0].style.display).toBe('')
  530. vm.ok = false
  531. waitForUpdate(() => {
  532. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  533. }).thenWaitFor(nextFrame).then(() => {
  534. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  535. }).thenWaitFor(duration + buffer).then(() => {
  536. expect(vm.$el.children[0].style.display).toBe('none')
  537. vm.ok = true
  538. }).then(() => {
  539. expect(vm.$el.children[0].style.display).toBe('')
  540. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  541. }).thenWaitFor(nextFrame).then(() => {
  542. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  543. }).thenWaitFor(duration + buffer).then(() => {
  544. expect(vm.$el.children[0].className).toBe('test')
  545. }).then(done)
  546. })
  547. it('leaveCancelled (v-show only)', done => {
  548. const spy = jasmine.createSpy('leaveCancelled')
  549. const vm = new Vue({
  550. template: `
  551. <div>
  552. <transition name="test" @leave-cancelled="leaveCancelled">
  553. <div v-show="ok" class="test">foo</div>
  554. </transition>
  555. </div>
  556. `,
  557. data: { ok: true },
  558. methods: {
  559. leaveCancelled: spy
  560. }
  561. }).$mount(el)
  562. expect(vm.$el.children[0].style.display).toBe('')
  563. vm.ok = false
  564. waitForUpdate(() => {
  565. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  566. }).thenWaitFor(nextFrame).then(() => {
  567. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  568. }).thenWaitFor(10).then(() => {
  569. vm.ok = true
  570. }).then(() => {
  571. expect(spy).toHaveBeenCalled()
  572. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  573. }).thenWaitFor(nextFrame).then(() => {
  574. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  575. }).thenWaitFor(duration + buffer).then(() => {
  576. expect(vm.$el.children[0].style.display).toBe('')
  577. }).then(done)
  578. })
  579. it('leave transition with v-show: cancelled on next frame', done => {
  580. const vm = new Vue({
  581. template: `
  582. <div>
  583. <transition name="test">
  584. <div v-show="ok" class="test">foo</div>
  585. </transition>
  586. </div>
  587. `,
  588. data: { ok: true }
  589. }).$mount(el)
  590. vm.ok = false
  591. waitForUpdate(() => {
  592. vm.ok = true
  593. }).thenWaitFor(nextFrame).then(() => {
  594. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  595. }).thenWaitFor(duration + buffer).then(() => {
  596. expect(vm.$el.children[0].className).toBe('test')
  597. }).then(done)
  598. })
  599. it('enter transition with v-show: cancelled on next frame', done => {
  600. const vm = new Vue({
  601. template: `
  602. <div>
  603. <transition name="test">
  604. <div v-show="ok" class="test">foo</div>
  605. </transition>
  606. </div>
  607. `,
  608. data: { ok: false }
  609. }).$mount(el)
  610. vm.ok = true
  611. waitForUpdate(() => {
  612. vm.ok = false
  613. }).thenWaitFor(nextFrame).then(() => {
  614. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  615. }).thenWaitFor(duration + buffer).then(() => {
  616. expect(vm.$el.children[0].className).toBe('test')
  617. }).then(done)
  618. })
  619. it('animations', done => {
  620. const vm = new Vue({
  621. template: `
  622. <div>
  623. <transition name="test-anim">
  624. <div v-if="ok">foo</div>
  625. </transition>
  626. </div>
  627. `,
  628. data: { ok: true }
  629. }).$mount(el)
  630. // should not apply transition on initial render by default
  631. expect(vm.$el.innerHTML).toBe('<div>foo</div>')
  632. vm.ok = false
  633. waitForUpdate(() => {
  634. expect(vm.$el.children[0].className).toBe('test-anim-leave test-anim-leave-active')
  635. }).thenWaitFor(nextFrame).then(() => {
  636. expect(vm.$el.children[0].className).toBe('test-anim-leave-active test-anim-leave-to')
  637. }).thenWaitFor(duration + buffer).then(() => {
  638. expect(vm.$el.children.length).toBe(0)
  639. vm.ok = true
  640. }).then(() => {
  641. expect(vm.$el.children[0].className).toBe('test-anim-enter test-anim-enter-active')
  642. }).thenWaitFor(nextFrame).then(() => {
  643. expect(vm.$el.children[0].className).toBe('test-anim-enter-active test-anim-enter-to')
  644. }).thenWaitFor(duration + buffer).then(() => {
  645. expect(vm.$el.children[0].className).toBe('')
  646. }).then(done)
  647. })
  648. it('explicit transition type', done => {
  649. const vm = new Vue({
  650. template: `
  651. <div>
  652. <transition name="test-anim-long" type="animation">
  653. <div v-if="ok" class="test">foo</div>
  654. </transition>
  655. </div>
  656. `,
  657. data: { ok: true }
  658. }).$mount(el)
  659. // should not apply transition on initial render by default
  660. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  661. vm.ok = false
  662. waitForUpdate(() => {
  663. expect(vm.$el.children[0].className).toBe('test test-anim-long-leave test-anim-long-leave-active')
  664. }).thenWaitFor(nextFrame).then(() => {
  665. expect(vm.$el.children[0].className).toBe('test test-anim-long-leave-active test-anim-long-leave-to')
  666. }).thenWaitFor(duration + 5).then(() => {
  667. // should not end early due to transition presence
  668. expect(vm.$el.children[0].className).toBe('test test-anim-long-leave-active test-anim-long-leave-to')
  669. }).thenWaitFor(duration + 5).then(() => {
  670. expect(vm.$el.children.length).toBe(0)
  671. vm.ok = true
  672. }).then(() => {
  673. expect(vm.$el.children[0].className).toBe('test test-anim-long-enter test-anim-long-enter-active')
  674. }).thenWaitFor(nextFrame).then(() => {
  675. expect(vm.$el.children[0].className).toBe('test test-anim-long-enter-active test-anim-long-enter-to')
  676. }).thenWaitFor(duration + 5).then(() => {
  677. expect(vm.$el.children[0].className).toBe('test test-anim-long-enter-active test-anim-long-enter-to')
  678. }).thenWaitFor(duration + 5).then(() => {
  679. expect(vm.$el.children[0].className).toBe('test')
  680. }).then(done)
  681. })
  682. it('transition on appear', done => {
  683. const vm = new Vue({
  684. template: `
  685. <div>
  686. <transition name="test"
  687. appear
  688. appear-class="test-appear"
  689. appear-to-class="test-appear-to"
  690. appear-active-class="test-appear-active">
  691. <div v-if="ok" class="test">foo</div>
  692. </transition>
  693. </div>
  694. `,
  695. data: { ok: true }
  696. }).$mount(el)
  697. waitForUpdate(() => {
  698. expect(vm.$el.children[0].className).toBe('test test-appear test-appear-active')
  699. }).thenWaitFor(nextFrame).then(() => {
  700. expect(vm.$el.children[0].className).toBe('test test-appear-active test-appear-to')
  701. }).thenWaitFor(duration + buffer).then(() => {
  702. expect(vm.$el.children[0].className).toBe('test')
  703. }).then(done)
  704. })
  705. it('transition on appear with v-show', done => {
  706. const vm = new Vue({
  707. template: `
  708. <div>
  709. <transition name="test" appear>
  710. <div v-show="ok" class="test">foo</div>
  711. </transition>
  712. </div>
  713. `,
  714. data: { ok: true }
  715. }).$mount(el)
  716. waitForUpdate(() => {
  717. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  718. }).thenWaitFor(nextFrame).then(() => {
  719. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  720. }).thenWaitFor(duration + buffer).then(() => {
  721. expect(vm.$el.children[0].className).toBe('test')
  722. }).then(done)
  723. })
  724. it('transition on SVG elements', done => {
  725. const vm = new Vue({
  726. template: `
  727. <svg>
  728. <transition>
  729. <circle cx="0" cy="0" r="10" v-if="ok" class="test"></circle>
  730. </transition>
  731. </svg>
  732. `,
  733. data: { ok: true }
  734. }).$mount(el)
  735. // should not apply transition on initial render by default
  736. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test')
  737. vm.ok = false
  738. waitForUpdate(() => {
  739. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test v-leave v-leave-active')
  740. }).thenWaitFor(nextFrame).then(() => {
  741. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test v-leave-active v-leave-to')
  742. }).thenWaitFor(duration + buffer).then(() => {
  743. expect(vm.$el.childNodes.length).toBe(1)
  744. expect(vm.$el.childNodes[0].nodeType).toBe(8) // should be an empty comment node
  745. expect(vm.$el.childNodes[0].textContent).toBe('')
  746. vm.ok = true
  747. }).then(() => {
  748. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test v-enter v-enter-active')
  749. }).thenWaitFor(nextFrame).then(() => {
  750. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test v-enter-active v-enter-to')
  751. }).thenWaitFor(duration + buffer).then(() => {
  752. expect(vm.$el.childNodes[0].getAttribute('class')).toBe('test')
  753. }).then(done)
  754. })
  755. it('transition on child components', done => {
  756. const vm = new Vue({
  757. template: `
  758. <div>
  759. <transition>
  760. <test v-if="ok" class="test"></test>
  761. </transition>
  762. </div>
  763. `,
  764. data: { ok: true },
  765. components: {
  766. test: {
  767. template: `
  768. <transition name="test">
  769. <div>foo</div>
  770. </transition>
  771. ` // test transition override from parent
  772. }
  773. }
  774. }).$mount(el)
  775. // should not apply transition on initial render by default
  776. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  777. vm.ok = false
  778. waitForUpdate(() => {
  779. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  780. }).thenWaitFor(nextFrame).then(() => {
  781. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  782. }).thenWaitFor(duration + buffer).then(() => {
  783. expect(vm.$el.children.length).toBe(0)
  784. vm.ok = true
  785. }).then(() => {
  786. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  787. }).thenWaitFor(nextFrame).then(() => {
  788. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  789. }).thenWaitFor(duration + buffer).then(() => {
  790. expect(vm.$el.children[0].className).toBe('test')
  791. }).then(done)
  792. })
  793. it('transition inside child component', done => {
  794. const vm = new Vue({
  795. template: `
  796. <div>
  797. <test v-if="ok" class="test"></test>
  798. </div>
  799. `,
  800. data: { ok: true },
  801. components: {
  802. test: {
  803. template: `
  804. <transition>
  805. <div>foo</div>
  806. </transition>
  807. `
  808. }
  809. }
  810. }).$mount(el)
  811. // should not apply transition on initial render by default
  812. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  813. vm.ok = false
  814. waitForUpdate(() => {
  815. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  816. }).thenWaitFor(nextFrame).then(() => {
  817. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  818. }).thenWaitFor(duration + buffer).then(() => {
  819. expect(vm.$el.children.length).toBe(0)
  820. vm.ok = true
  821. }).then(() => {
  822. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  823. }).thenWaitFor(nextFrame).then(() => {
  824. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  825. }).thenWaitFor(duration + buffer).then(() => {
  826. expect(vm.$el.children[0].className).toBe('test')
  827. }).then(done)
  828. })
  829. it('custom transition higher-order component', done => {
  830. const vm = new Vue({
  831. template: '<div><my-transition><div v-if="ok" class="test">foo</div></my-transition></div>',
  832. data: { ok: true },
  833. components: {
  834. 'my-transition': {
  835. functional: true,
  836. render (h, { data, children }) {
  837. (data.props || (data.props = {})).name = 'test'
  838. return h('transition', data, children)
  839. }
  840. }
  841. }
  842. }).$mount(el)
  843. // should not apply transition on initial render by default
  844. expect(vm.$el.innerHTML).toBe('<div class="test">foo</div>')
  845. vm.ok = false
  846. waitForUpdate(() => {
  847. expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
  848. }).thenWaitFor(nextFrame).then(() => {
  849. expect(vm.$el.children[0].className).toBe('test test-leave-active test-leave-to')
  850. }).thenWaitFor(duration + buffer).then(() => {
  851. expect(vm.$el.children.length).toBe(0)
  852. vm.ok = true
  853. }).then(() => {
  854. expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
  855. }).thenWaitFor(nextFrame).then(() => {
  856. expect(vm.$el.children[0].className).toBe('test test-enter-active test-enter-to')
  857. }).thenWaitFor(duration + buffer).then(() => {
  858. expect(vm.$el.children[0].className).toBe('test')
  859. }).then(done)
  860. })
  861. it('warn when used on multiple elements', () => {
  862. new Vue({
  863. template: `<transition><p>1</p><p>2</p></transition>`
  864. }).$mount()
  865. expect(`<transition> can only be used on a single element`).toHaveBeenWarned()
  866. })
  867. describe('explicit durations -', () => {
  868. it('single value', done => {
  869. const vm = new Vue({
  870. template: `
  871. <div>
  872. <transition duration="${explicitDuration}">
  873. <div v-if="ok" class="test">foo</div>
  874. </transition>
  875. </div>
  876. `,
  877. data: { ok: true }
  878. }).$mount(el)
  879. vm.ok = false
  880. waitForUpdate(() => {
  881. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  882. }).thenWaitFor(nextFrame).then(() => {
  883. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  884. }).thenWaitFor(explicitDuration + buffer).then(() => {
  885. expect(vm.$el.children.length).toBe(0)
  886. vm.ok = true
  887. }).then(() => {
  888. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  889. }).thenWaitFor(nextFrame).then(() => {
  890. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  891. }).thenWaitFor(explicitDuration + buffer).then(() => {
  892. expect(vm.$el.children[0].className).toBe('test')
  893. }).then(done)
  894. })
  895. it('enter and auto leave', done => {
  896. const vm = new Vue({
  897. template: `
  898. <div>
  899. <transition :duration="{ enter: ${explicitDuration} }">
  900. <div v-if="ok" class="test">foo</div>
  901. </transition>
  902. </div>
  903. `,
  904. data: { ok: true }
  905. }).$mount(el)
  906. vm.ok = false
  907. waitForUpdate(() => {
  908. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  909. }).thenWaitFor(nextFrame).then(() => {
  910. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  911. }).thenWaitFor(duration + buffer).then(() => {
  912. expect(vm.$el.children.length).toBe(0)
  913. vm.ok = true
  914. }).then(() => {
  915. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  916. }).thenWaitFor(nextFrame).then(() => {
  917. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  918. }).thenWaitFor(explicitDuration + buffer).then(() => {
  919. expect(vm.$el.children[0].className).toBe('test')
  920. }).then(done)
  921. })
  922. it('leave and auto enter', done => {
  923. const vm = new Vue({
  924. template: `
  925. <div>
  926. <transition :duration="{ leave: ${explicitDuration} }">
  927. <div v-if="ok" class="test">foo</div>
  928. </transition>
  929. </div>
  930. `,
  931. data: { ok: true }
  932. }).$mount(el)
  933. vm.ok = false
  934. waitForUpdate(() => {
  935. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  936. }).thenWaitFor(nextFrame).then(() => {
  937. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  938. }).thenWaitFor(explicitDuration + buffer).then(() => {
  939. expect(vm.$el.children.length).toBe(0)
  940. vm.ok = true
  941. }).then(() => {
  942. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  943. }).thenWaitFor(nextFrame).then(() => {
  944. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  945. }).thenWaitFor(duration + buffer).then(() => {
  946. expect(vm.$el.children[0].className).toBe('test')
  947. }).then(done)
  948. })
  949. it('separate enter and leave', done => {
  950. const enter = explicitDuration
  951. const leave = explicitDuration * 2
  952. const vm = new Vue({
  953. template: `
  954. <div>
  955. <transition :duration="{ enter: ${enter}, leave: ${leave} }">
  956. <div v-if="ok" class="test">foo</div>
  957. </transition>
  958. </div>
  959. `,
  960. data: { ok: true }
  961. }).$mount(el)
  962. vm.ok = false
  963. waitForUpdate(() => {
  964. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  965. }).thenWaitFor(nextFrame).then(() => {
  966. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  967. }).thenWaitFor(leave + buffer).then(() => {
  968. expect(vm.$el.children.length).toBe(0)
  969. vm.ok = true
  970. }).then(() => {
  971. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  972. }).thenWaitFor(nextFrame).then(() => {
  973. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  974. }).thenWaitFor(enter + buffer).then(() => {
  975. expect(vm.$el.children[0].className).toBe('test')
  976. }).then(done)
  977. })
  978. it('enter and leave + duration change', done => {
  979. const enter1 = explicitDuration * 2
  980. const enter2 = explicitDuration
  981. const leave1 = explicitDuration * 0.5
  982. const leave2 = explicitDuration * 3
  983. const vm = new Vue({
  984. template: `
  985. <div>
  986. <transition :duration="{ enter: enter, leave: leave }">
  987. <div v-if="ok" class="test">foo</div>
  988. </transition>
  989. </div>
  990. `,
  991. data: {
  992. ok: true,
  993. enter: enter1,
  994. leave: leave1
  995. }
  996. }).$mount(el)
  997. vm.ok = false
  998. waitForUpdate(() => {
  999. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  1000. }).thenWaitFor(nextFrame).then(() => {
  1001. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  1002. }).thenWaitFor(leave1 + buffer).then(() => {
  1003. expect(vm.$el.children.length).toBe(0)
  1004. vm.ok = true
  1005. }).then(() => {
  1006. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  1007. }).thenWaitFor(nextFrame).then(() => {
  1008. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  1009. }).thenWaitFor(enter1 + buffer).then(() => {
  1010. expect(vm.$el.children[0].className).toBe('test')
  1011. vm.enter = enter2
  1012. vm.leave = leave2
  1013. }).then(() => {
  1014. vm.ok = false
  1015. }).then(() => {
  1016. expect(vm.$el.children[0].className).toBe('test v-leave v-leave-active')
  1017. }).thenWaitFor(nextFrame).then(() => {
  1018. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  1019. }).thenWaitFor(leave2 + buffer).then(() => {
  1020. expect(vm.$el.children.length).toBe(0)
  1021. vm.ok = true
  1022. }).then(() => {
  1023. expect(vm.$el.children[0].className).toBe('test v-enter v-enter-active')
  1024. }).thenWaitFor(nextFrame).then(() => {
  1025. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  1026. }).thenWaitFor(enter2 + buffer).then(() => {
  1027. expect(vm.$el.children[0].className).toBe('test')
  1028. }).then(done)
  1029. }, 10000)
  1030. it('warn invalid durations', done => {
  1031. const vm = new Vue({
  1032. template: `
  1033. <div>
  1034. <transition :duration="{ enter: NaN, leave: 'foo' }">
  1035. <div v-if="ok" class="test">foo</div>
  1036. </transition>
  1037. </div>
  1038. `,
  1039. data: {
  1040. ok: true
  1041. }
  1042. }).$mount(el)
  1043. vm.ok = false
  1044. waitForUpdate(() => {
  1045. expect(`<transition> explicit leave duration is not a valid number - got "foo"`).toHaveBeenWarned()
  1046. }).thenWaitFor(duration + buffer).then(() => {
  1047. vm.ok = true
  1048. }).then(() => {
  1049. expect(`<transition> explicit enter duration is NaN`).toHaveBeenWarned()
  1050. }).then(done)
  1051. })
  1052. })
  1053. // #6687
  1054. it('transition on child components with empty root node', done => {
  1055. const vm = new Vue({
  1056. template: `
  1057. <div>
  1058. <transition mode="out-in">
  1059. <component class="test" :is="view"></component>
  1060. </transition>
  1061. </div>
  1062. `,
  1063. data: { view: 'one' },
  1064. components: {
  1065. 'one': {
  1066. template: '<div v-if="false">one</div>'
  1067. },
  1068. 'two': {
  1069. template: '<div>two</div>'
  1070. }
  1071. }
  1072. }).$mount(el)
  1073. // should not apply transition on initial render by default
  1074. expect(vm.$el.innerHTML).toBe('<!---->')
  1075. vm.view = 'two'
  1076. waitForUpdate(() => {
  1077. expect(vm.$el.innerHTML).toBe('<div class="test v-enter v-enter-active">two</div>')
  1078. }).thenWaitFor(nextFrame).then(() => {
  1079. expect(vm.$el.children[0].className).toBe('test v-enter-active v-enter-to')
  1080. }).thenWaitFor(duration + buffer).then(() => {
  1081. expect(vm.$el.children[0].className).toBe('test')
  1082. vm.view = 'one'
  1083. }).then(() => {
  1084. // incoming comment node is appended instantly because it doesn't have
  1085. // data and therefore doesn't go through the transition module.
  1086. expect(vm.$el.innerHTML).toBe('<div class="test v-leave v-leave-active">two</div><!---->')
  1087. }).thenWaitFor(nextFrame).then(() => {
  1088. expect(vm.$el.children[0].className).toBe('test v-leave-active v-leave-to')
  1089. }).thenWaitFor(duration + buffer).then(() => {
  1090. expect(vm.$el.innerHTML).toBe('<!---->')
  1091. }).then(done)
  1092. })
  1093. // #8199
  1094. it('should not throw error when replaced by v-html contents', (done) => {
  1095. const vm = new Vue({
  1096. template: `
  1097. <div>
  1098. <div v-if="ok" :class="ok">
  1099. <transition>
  1100. <span>a</span>
  1101. </transition>
  1102. </div>
  1103. <div v-else v-html="ok"></div>
  1104. </div>
  1105. `,
  1106. data: { ok: true }
  1107. }).$mount(el)
  1108. vm.ok = false
  1109. waitForUpdate(() => {
  1110. expect(vm.$el.children[0].innerHTML).toBe('false')
  1111. }).then(done)
  1112. })
  1113. })
  1114. }