transition-mode.spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. import Vue from 'vue'
  2. import injectStyles from './inject-styles'
  3. import { isIE9 } from 'web/util/index'
  4. import { nextFrame } from 'web/runtime/transition-util'
  5. if (!isIE9) {
  6. describe('Transition mode', () => {
  7. const duration = injectStyles()
  8. const components = {
  9. one: { template: '<div>one</div>' },
  10. two: { template: '<div>two</div>' }
  11. }
  12. let el
  13. beforeEach(() => {
  14. el = document.createElement('div')
  15. document.body.appendChild(el)
  16. })
  17. it('dynamic components, simultaneous', done => {
  18. const vm = new Vue({
  19. template: `<div>
  20. <transition>
  21. <component :is="view" class="test">
  22. </component>
  23. </transition>
  24. </div>`,
  25. data: { view: 'one' },
  26. components
  27. }).$mount(el)
  28. expect(vm.$el.textContent).toBe('one')
  29. vm.view = 'two'
  30. waitForUpdate(() => {
  31. expect(vm.$el.innerHTML).toBe(
  32. '<div class="test v-leave v-leave-active">one</div>' +
  33. '<div class="test v-enter v-enter-active">two</div>'
  34. )
  35. }).thenWaitFor(nextFrame).then(() => {
  36. expect(vm.$el.innerHTML).toBe(
  37. '<div class="test v-leave-active">one</div>' +
  38. '<div class="test v-enter-active">two</div>'
  39. )
  40. }).thenWaitFor(duration + 10).then(() => {
  41. expect(vm.$el.innerHTML).toBe(
  42. '<div class="test">two</div>'
  43. )
  44. }).then(done)
  45. })
  46. it('dynamic components, out-in', done => {
  47. let next
  48. const vm = new Vue({
  49. template: `<div>
  50. <transition name="test" mode="out-in" @after-leave="afterLeave">
  51. <component :is="view" class="test">
  52. </component>
  53. </transition>
  54. </div>`,
  55. data: { view: 'one' },
  56. components,
  57. methods: {
  58. afterLeave () {
  59. next()
  60. }
  61. }
  62. }).$mount(el)
  63. expect(vm.$el.textContent).toBe('one')
  64. vm.view = 'two'
  65. waitForUpdate(() => {
  66. expect(vm.$el.innerHTML).toBe(
  67. '<div class="test test-leave test-leave-active">one</div>'
  68. )
  69. }).thenWaitFor(nextFrame).then(() => {
  70. expect(vm.$el.innerHTML).toBe(
  71. '<div class="test test-leave-active">one</div>'
  72. )
  73. }).thenWaitFor(_next => { next = _next }).then(() => {
  74. expect(vm.$el.innerHTML).toBe('')
  75. }).thenWaitFor(nextFrame).then(() => {
  76. expect(vm.$el.innerHTML).toBe(
  77. '<div class="test test-enter test-enter-active">two</div>'
  78. )
  79. }).thenWaitFor(nextFrame).then(() => {
  80. expect(vm.$el.innerHTML).toBe(
  81. '<div class="test test-enter-active">two</div>'
  82. )
  83. }).thenWaitFor(duration + 10).then(() => {
  84. expect(vm.$el.innerHTML).toBe(
  85. '<div class="test">two</div>'
  86. )
  87. }).then(done)
  88. })
  89. it('dynamic components, in-out', done => {
  90. let next
  91. const vm = new Vue({
  92. template: `<div>
  93. <transition name="test" mode="in-out" @after-enter="afterEnter">
  94. <component :is="view" class="test">
  95. </component>
  96. </transition>
  97. </div>`,
  98. data: { view: 'one' },
  99. components,
  100. methods: {
  101. afterEnter () {
  102. next()
  103. }
  104. }
  105. }).$mount(el)
  106. expect(vm.$el.textContent).toBe('one')
  107. vm.view = 'two'
  108. waitForUpdate(() => {
  109. expect(vm.$el.innerHTML).toBe(
  110. '<div class="test">one</div>' +
  111. '<div class="test test-enter test-enter-active">two</div>'
  112. )
  113. }).thenWaitFor(nextFrame).then(() => {
  114. expect(vm.$el.innerHTML).toBe(
  115. '<div class="test">one</div>' +
  116. '<div class="test test-enter-active">two</div>'
  117. )
  118. }).thenWaitFor(_next => { next = _next }).then(() => {
  119. expect(vm.$el.innerHTML).toBe(
  120. '<div class="test">one</div>' +
  121. '<div class="test">two</div>'
  122. )
  123. }).then(() => {
  124. expect(vm.$el.innerHTML).toBe(
  125. '<div class="test test-leave test-leave-active">one</div>' +
  126. '<div class="test">two</div>'
  127. )
  128. }).thenWaitFor(nextFrame).then(() => {
  129. expect(vm.$el.innerHTML).toBe(
  130. '<div class="test test-leave-active">one</div>' +
  131. '<div class="test">two</div>'
  132. )
  133. }).thenWaitFor(duration + 10).then(() => {
  134. expect(vm.$el.innerHTML).toBe(
  135. '<div class="test">two</div>'
  136. )
  137. }).then(done)
  138. })
  139. it('dynamic components, in-out with early cancel', done => {
  140. let next
  141. const vm = new Vue({
  142. template: `<div>
  143. <transition name="test" mode="in-out" @after-enter="afterEnter">
  144. <component :is="view" class="test"></component>
  145. </transition>
  146. </div>`,
  147. data: { view: 'one' },
  148. components,
  149. methods: {
  150. afterEnter () {
  151. next()
  152. }
  153. }
  154. }).$mount(el)
  155. expect(vm.$el.textContent).toBe('one')
  156. vm.view = 'two'
  157. waitForUpdate(() => {
  158. expect(vm.$el.innerHTML).toBe(
  159. '<div class="test">one</div>' +
  160. '<div class="test test-enter test-enter-active">two</div>'
  161. )
  162. }).thenWaitFor(nextFrame).then(() => {
  163. expect(vm.$el.innerHTML).toBe(
  164. '<div class="test">one</div>' +
  165. '<div class="test test-enter-active">two</div>'
  166. )
  167. // switch again before enter finishes,
  168. // this cancels both enter and leave.
  169. vm.view = 'one'
  170. }).then(() => {
  171. // 1. the pending leaving "one" should be removed instantly.
  172. // 2. the entering "two" should be placed into its final state instantly.
  173. // 3. a new "one" is created and entering
  174. expect(vm.$el.innerHTML).toBe(
  175. '<div class="test">two</div>' +
  176. '<div class="test test-enter test-enter-active">one</div>'
  177. )
  178. }).thenWaitFor(nextFrame).then(() => {
  179. expect(vm.$el.innerHTML).toBe(
  180. '<div class="test">two</div>' +
  181. '<div class="test test-enter-active">one</div>'
  182. )
  183. }).thenWaitFor(_next => { next = _next }).then(() => {
  184. expect(vm.$el.innerHTML).toBe(
  185. '<div class="test">two</div>' +
  186. '<div class="test">one</div>'
  187. )
  188. }).then(() => {
  189. expect(vm.$el.innerHTML).toBe(
  190. '<div class="test test-leave test-leave-active">two</div>' +
  191. '<div class="test">one</div>'
  192. )
  193. }).thenWaitFor(nextFrame).then(() => {
  194. expect(vm.$el.innerHTML).toBe(
  195. '<div class="test test-leave-active">two</div>' +
  196. '<div class="test">one</div>'
  197. )
  198. }).thenWaitFor(duration + 10).then(() => {
  199. expect(vm.$el.innerHTML).toBe(
  200. '<div class="test">one</div>'
  201. )
  202. }).then(done).then(done)
  203. })
  204. it('normal elements with different keys, simultaneous', done => {
  205. const vm = new Vue({
  206. template: `<div>
  207. <transition>
  208. <div :key="view" class="test">{{view}}</div>
  209. </transition>
  210. </div>`,
  211. data: { view: 'one' },
  212. components
  213. }).$mount(el)
  214. expect(vm.$el.textContent).toBe('one')
  215. vm.view = 'two'
  216. waitForUpdate(() => {
  217. expect(vm.$el.innerHTML).toBe(
  218. '<div class="test v-leave v-leave-active">one</div>' +
  219. '<div class="test v-enter v-enter-active">two</div>'
  220. )
  221. }).thenWaitFor(nextFrame).then(() => {
  222. expect(vm.$el.innerHTML).toBe(
  223. '<div class="test v-leave-active">one</div>' +
  224. '<div class="test v-enter-active">two</div>'
  225. )
  226. }).thenWaitFor(duration + 10).then(() => {
  227. expect(vm.$el.innerHTML).toBe(
  228. '<div class="test">two</div>'
  229. )
  230. }).then(done)
  231. })
  232. it('normal elements with different keys, out-in', done => {
  233. let next
  234. const vm = new Vue({
  235. template: `<div>
  236. <transition name="test" mode="out-in" @after-leave="afterLeave">
  237. <div :key="view" class="test">{{view}}</div>
  238. </transition>
  239. </div>`,
  240. data: { view: 'one' },
  241. components,
  242. methods: {
  243. afterLeave () {
  244. next()
  245. }
  246. }
  247. }).$mount(el)
  248. expect(vm.$el.textContent).toBe('one')
  249. vm.view = 'two'
  250. waitForUpdate(() => {
  251. expect(vm.$el.innerHTML).toBe(
  252. '<div class="test test-leave test-leave-active">one</div>'
  253. )
  254. }).thenWaitFor(nextFrame).then(() => {
  255. expect(vm.$el.innerHTML).toBe(
  256. '<div class="test test-leave-active">one</div>'
  257. )
  258. }).thenWaitFor(_next => { next = _next }).then(() => {
  259. expect(vm.$el.innerHTML).toBe('')
  260. }).thenWaitFor(nextFrame).then(() => {
  261. expect(vm.$el.innerHTML).toBe(
  262. '<div class="test test-enter test-enter-active">two</div>'
  263. )
  264. }).thenWaitFor(nextFrame).then(() => {
  265. expect(vm.$el.innerHTML).toBe(
  266. '<div class="test test-enter-active">two</div>'
  267. )
  268. }).thenWaitFor(duration + 10).then(() => {
  269. expect(vm.$el.innerHTML).toBe(
  270. '<div class="test">two</div>'
  271. )
  272. }).then(done)
  273. })
  274. it('normal elements with different keys, in-out', done => {
  275. let next
  276. const vm = new Vue({
  277. template: `<div>
  278. <transition name="test" mode="in-out" @after-enter="afterEnter">
  279. <div :key="view" class="test">{{view}}</div>
  280. </transition>
  281. </div>`,
  282. data: { view: 'one' },
  283. components,
  284. methods: {
  285. afterEnter () {
  286. next()
  287. }
  288. }
  289. }).$mount(el)
  290. expect(vm.$el.textContent).toBe('one')
  291. vm.view = 'two'
  292. waitForUpdate(() => {
  293. expect(vm.$el.innerHTML).toBe(
  294. '<div class="test">one</div>' +
  295. '<div class="test test-enter test-enter-active">two</div>'
  296. )
  297. }).thenWaitFor(nextFrame).then(() => {
  298. expect(vm.$el.innerHTML).toBe(
  299. '<div class="test">one</div>' +
  300. '<div class="test test-enter-active">two</div>'
  301. )
  302. }).thenWaitFor(_next => { next = _next }).then(() => {
  303. expect(vm.$el.innerHTML).toBe(
  304. '<div class="test">one</div>' +
  305. '<div class="test">two</div>'
  306. )
  307. }).then(() => {
  308. expect(vm.$el.innerHTML).toBe(
  309. '<div class="test test-leave test-leave-active">one</div>' +
  310. '<div class="test">two</div>'
  311. )
  312. }).thenWaitFor(nextFrame).then(() => {
  313. expect(vm.$el.innerHTML).toBe(
  314. '<div class="test test-leave-active">one</div>' +
  315. '<div class="test">two</div>'
  316. )
  317. }).thenWaitFor(duration + 10).then(() => {
  318. expect(vm.$el.innerHTML).toBe(
  319. '<div class="test">two</div>'
  320. )
  321. }).then(done)
  322. })
  323. it('warn invaid mode', () => {
  324. new Vue({
  325. template: '<transition mode="foo"><div>123</div></transition>'
  326. }).$mount()
  327. expect('invalid <transition> mode: foo').toHaveBeenWarned()
  328. })
  329. it('warn usage on non element/component', () => {
  330. new Vue({
  331. template: '<transition mode="foo">foo</transition>'
  332. }).$mount()
  333. expect('<transition> can only be used on elements or components, not text nodes.').toHaveBeenWarned()
  334. })
  335. })
  336. }