transition-group.spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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 group', () => {
  7. const { duration, buffer } = injectStyles()
  8. let el
  9. beforeEach(() => {
  10. el = document.createElement('div')
  11. document.body.appendChild(el)
  12. })
  13. function createBasicVM (useIs, appear) {
  14. const vm = new Vue({
  15. template: `
  16. <div>
  17. ${useIs ? `<span is="transition-group">` : `<transition-group${appear ? ` appear` : ``}>`}
  18. <div v-for="item in items" :key="item" class="test">{{ item }}</div>
  19. ${useIs ? `</span>` : `</transition-group>`}
  20. </div>
  21. `,
  22. data: {
  23. items: ['a', 'b', 'c']
  24. }
  25. }).$mount(el)
  26. if (!appear) {
  27. expect(vm.$el.innerHTML).toBe(
  28. `<span>` +
  29. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  30. `</span>`
  31. )
  32. }
  33. return vm
  34. }
  35. it('enter', done => {
  36. const vm = createBasicVM()
  37. vm.items.push('d', 'e')
  38. waitForUpdate(() => {
  39. expect(vm.$el.innerHTML).toBe(
  40. `<span>` +
  41. ['a', 'b', 'c'].map(i => `<div class="test">${i}</div>`).join('') +
  42. `<div class="test v-enter v-enter-active">d</div>` +
  43. `<div class="test v-enter v-enter-active">e</div>` +
  44. `</span>`
  45. )
  46. }).thenWaitFor(nextFrame).then(() => {
  47. expect(vm.$el.innerHTML).toBe(
  48. `<span>` +
  49. ['a', 'b', 'c'].map(i => `<div class="test">${i}</div>`).join('') +
  50. `<div class="test v-enter-active v-enter-to">d</div>` +
  51. `<div class="test v-enter-active v-enter-to">e</div>` +
  52. `</span>`
  53. )
  54. }).thenWaitFor(duration + buffer).then(() => {
  55. expect(vm.$el.innerHTML).toBe(
  56. `<span>` +
  57. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  58. `</span>`
  59. )
  60. }).then(done)
  61. })
  62. it('leave', done => {
  63. const vm = createBasicVM()
  64. vm.items = ['b']
  65. waitForUpdate(() => {
  66. expect(vm.$el.innerHTML).toBe(
  67. `<span>` +
  68. `<div class="test v-leave v-leave-active">a</div>` +
  69. `<div class="test">b</div>` +
  70. `<div class="test v-leave v-leave-active">c</div>` +
  71. `</span>`
  72. )
  73. }).thenWaitFor(nextFrame).then(() => {
  74. expect(vm.$el.innerHTML).toBe(
  75. `<span>` +
  76. `<div class="test v-leave-active v-leave-to">a</div>` +
  77. `<div class="test">b</div>` +
  78. `<div class="test v-leave-active v-leave-to">c</div>` +
  79. `</span>`
  80. )
  81. }).thenWaitFor(duration + buffer).then(() => {
  82. expect(vm.$el.innerHTML).toBe(
  83. `<span>` +
  84. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  85. `</span>`
  86. )
  87. }).then(done)
  88. })
  89. it('enter + leave', done => {
  90. const vm = createBasicVM()
  91. vm.items = ['b', 'c', 'd']
  92. waitForUpdate(() => {
  93. expect(vm.$el.innerHTML).toBe(
  94. `<span>` +
  95. `<div class="test v-leave v-leave-active">a</div>` +
  96. `<div class="test">b</div>` +
  97. `<div class="test">c</div>` +
  98. `<div class="test v-enter v-enter-active">d</div>` +
  99. `</span>`
  100. )
  101. }).thenWaitFor(nextFrame).then(() => {
  102. expect(vm.$el.innerHTML).toBe(
  103. `<span>` +
  104. `<div class="test v-leave-active v-leave-to">a</div>` +
  105. `<div class="test">b</div>` +
  106. `<div class="test">c</div>` +
  107. `<div class="test v-enter-active v-enter-to">d</div>` +
  108. `</span>`
  109. )
  110. }).thenWaitFor(duration + buffer).then(() => {
  111. expect(vm.$el.innerHTML).toBe(
  112. `<span>` +
  113. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  114. `</span>`
  115. )
  116. }).then(done)
  117. })
  118. it('use with "is" attribute', done => {
  119. const vm = createBasicVM(true)
  120. vm.items = ['b', 'c', 'd']
  121. waitForUpdate(() => {
  122. expect(vm.$el.innerHTML).toBe(
  123. `<span>` +
  124. `<div class="test v-leave v-leave-active">a</div>` +
  125. `<div class="test">b</div>` +
  126. `<div class="test">c</div>` +
  127. `<div class="test v-enter v-enter-active">d</div>` +
  128. `</span>`
  129. )
  130. }).thenWaitFor(nextFrame).then(() => {
  131. expect(vm.$el.innerHTML).toBe(
  132. `<span>` +
  133. `<div class="test v-leave-active v-leave-to">a</div>` +
  134. `<div class="test">b</div>` +
  135. `<div class="test">c</div>` +
  136. `<div class="test v-enter-active v-enter-to">d</div>` +
  137. `</span>`
  138. )
  139. }).thenWaitFor(duration + buffer).then(() => {
  140. expect(vm.$el.innerHTML).toBe(
  141. `<span>` +
  142. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  143. `</span>`
  144. )
  145. }).then(done)
  146. })
  147. it('appear', done => {
  148. const vm = createBasicVM(false, true /* appear */)
  149. waitForUpdate(() => {
  150. expect(vm.$el.innerHTML).toBe(
  151. `<span>` +
  152. vm.items.map(i => `<div class="test v-enter v-enter-active">${i}</div>`).join('') +
  153. `</span>`
  154. )
  155. }).thenWaitFor(nextFrame).then(() => {
  156. expect(vm.$el.innerHTML).toBe(
  157. `<span>` +
  158. vm.items.map(i => `<div class="test v-enter-active v-enter-to">${i}</div>`).join('') +
  159. `</span>`
  160. )
  161. }).thenWaitFor(duration + buffer).then(() => {
  162. expect(vm.$el.innerHTML).toBe(
  163. `<span>` +
  164. vm.items.map(i => `<div class="test">${i}</div>`).join('') +
  165. `</span>`
  166. )
  167. }).then(done)
  168. })
  169. it('events', done => {
  170. let next
  171. const beforeEnterSpy = jasmine.createSpy()
  172. const afterEnterSpy = jasmine.createSpy()
  173. const afterLeaveSpy = jasmine.createSpy()
  174. const vm = new Vue({
  175. template: `
  176. <div>
  177. <transition-group @before-enter="beforeEnter" @after-enter="afterEnter" @after-leave="afterLeave">
  178. <div v-for="item in items" :key="item" class="test">{{ item }}</div>
  179. </transition-group>
  180. </div>
  181. `,
  182. data: {
  183. items: ['a', 'b', 'c']
  184. },
  185. methods: {
  186. beforeEnter (el) {
  187. expect(el.textContent).toBe('d')
  188. beforeEnterSpy()
  189. },
  190. afterEnter (el) {
  191. expect(el.textContent).toBe('d')
  192. afterEnterSpy()
  193. next()
  194. },
  195. afterLeave (el) {
  196. expect(el.textContent).toBe('a')
  197. afterLeaveSpy()
  198. next()
  199. }
  200. }
  201. }).$mount(el)
  202. vm.items.push('d')
  203. waitForUpdate(() => {
  204. expect(vm.$el.innerHTML).toBe(
  205. `<span>` +
  206. `<div class="test">a</div>` +
  207. `<div class="test">b</div>` +
  208. `<div class="test">c</div>` +
  209. `<div class="test v-enter v-enter-active">d</div>` +
  210. `</span>`
  211. )
  212. expect(beforeEnterSpy.calls.count()).toBe(1)
  213. }).thenWaitFor(_next => { next = _next }).then(() => {
  214. expect(vm.$el.innerHTML).toBe(
  215. `<span>` +
  216. `<div class="test">a</div>` +
  217. `<div class="test">b</div>` +
  218. `<div class="test">c</div>` +
  219. `<div class="test">d</div>` +
  220. `</span>`
  221. )
  222. expect(afterEnterSpy.calls.count()).toBe(1)
  223. vm.items.shift()
  224. }).thenWaitFor(_next => { next = _next }).then(() => {
  225. expect(vm.$el.innerHTML).toBe(
  226. `<span>` +
  227. `<div class="test">b</div>` +
  228. `<div class="test">c</div>` +
  229. `<div class="test">d</div>` +
  230. `</span>`
  231. )
  232. expect(afterLeaveSpy.calls.count()).toBe(1)
  233. }).then(done)
  234. })
  235. it('move', done => {
  236. const vm = new Vue({
  237. template: `
  238. <div>
  239. <transition-group name="group">
  240. <div v-for="item in items" :key="item" class="test">{{ item }}</div>
  241. </transition-group>
  242. </div>
  243. `,
  244. data: {
  245. items: ['a', 'b', 'c']
  246. }
  247. }).$mount(el)
  248. vm.items = ['d', 'b', 'a']
  249. waitForUpdate(() => {
  250. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  251. `<span>` +
  252. `<div class="test group-enter group-enter-active">d</div>` +
  253. `<div class="test">b</div>` +
  254. `<div class="test group-move">a</div>` +
  255. `<div class="test group-leave group-leave-active group-move">c</div>` +
  256. `</span>`
  257. )
  258. }).thenWaitFor(nextFrame).then(() => {
  259. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  260. `<span>` +
  261. `<div class="test group-enter-active group-enter-to">d</div>` +
  262. `<div class="test">b</div>` +
  263. `<div class="test group-move">a</div>` +
  264. `<div class="test group-leave-active group-move group-leave-to">c</div>` +
  265. `</span>`
  266. )
  267. }).thenWaitFor(duration * 2).then(() => {
  268. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  269. `<span>` +
  270. `<div class="test">d</div>` +
  271. `<div class="test">b</div>` +
  272. `<div class="test">a</div>` +
  273. `</span>`
  274. )
  275. }).then(done)
  276. })
  277. it('warn unkeyed children', () => {
  278. new Vue({
  279. template: `<div><transition-group><div v-for="i in 3"></div></transition-group></div>`
  280. }).$mount()
  281. expect('<transition-group> children must be keyed: <div>').toHaveBeenWarned()
  282. })
  283. // GitHub issue #6006
  284. it('should work with dynamic name', done => {
  285. const vm = new Vue({
  286. template: `
  287. <div>
  288. <transition-group :name="name">
  289. <div v-for="item in items" :key="item">{{ item }}</div>
  290. </transition-group>
  291. </div>
  292. `,
  293. data: {
  294. items: ['a', 'b', 'c'],
  295. name: 'group'
  296. }
  297. }).$mount(el)
  298. vm.name = 'invalid-name'
  299. vm.items = ['b', 'c', 'a']
  300. waitForUpdate(() => {
  301. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  302. `<span>` +
  303. `<div>b</div>` +
  304. `<div>c</div>` +
  305. `<div>a</div>` +
  306. `</span>`
  307. )
  308. vm.name = 'group'
  309. vm.items = ['a', 'b', 'c']
  310. }).thenWaitFor(nextFrame).then(() => {
  311. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  312. `<span>` +
  313. `<div class="group-move">a</div>` +
  314. `<div class="group-move">b</div>` +
  315. `<div class="group-move">c</div>` +
  316. `</span>`
  317. )
  318. }).thenWaitFor(duration * 2 + buffer).then(() => {
  319. expect(vm.$el.innerHTML.replace(/\s?style=""(\s?)/g, '$1')).toBe(
  320. `<span>` +
  321. `<div>a</div>` +
  322. `<div>b</div>` +
  323. `<div>c</div>` +
  324. `</span>`
  325. )
  326. }).then(done)
  327. })
  328. })
  329. }