github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/test/unit/specs/transition/transition_spec.js (about) 1 var Vue = require('src') 2 var _ = require('src/util') 3 var transition = require('src/transition') 4 var Transition = require('src/transition/transition') 5 6 if (!_.isIE9) { 7 describe('Transition', function () { 8 // insert a test css 9 function insertCSS (text) { 10 var cssEl = document.createElement('style') 11 cssEl.textContent = text 12 document.head.appendChild(cssEl) 13 } 14 15 var duration = 100 16 insertCSS( 17 '.test {\ 18 transition: opacity ' + duration + 'ms ease;\ 19 -webkit-transition: opacity ' + duration + 'ms ease;}' 20 ) 21 insertCSS('.test-enter, .test-leave { opacity: 0; }') 22 insertCSS( 23 '.test-anim-enter {\ 24 animation: test-enter ' + duration + 'ms;\ 25 -webkit-animation: test-enter ' + duration + 'ms;}\ 26 .test-anim-leave {\ 27 animation: test-leave ' + duration + 'ms;\ 28 -webkit-animation: test-leave ' + duration + 'ms;}\ 29 @keyframes test-enter {\ 30 from { opacity: 0 }\ 31 to { opacity: 1 }}\ 32 @-webkit-keyframes test-enter {\ 33 from { opacity: 0 }\ 34 to { opacity: 1 }}\ 35 @keyframes test-leave {\ 36 from { opacity: 1 }\ 37 to { opacity: 0 }}\ 38 @-webkit-keyframes test-leave {\ 39 from { opacity: 1 }\ 40 to { opacity: 0 }}' 41 ) 42 43 describe('Wrapper methods', function () { 44 var spy, el, target, parent, vm 45 beforeEach(function () { 46 el = document.createElement('div') 47 target = document.createElement('div') 48 parent = document.createElement('div') 49 parent.appendChild(target) 50 spy = jasmine.createSpy('transition skip') 51 vm = new Vue() 52 spyOn(transition, 'applyTransition') 53 }) 54 55 it('append', function () { 56 transition.appendWithTransition(el, parent, vm, spy) 57 expect(parent.lastChild).toBe(el) 58 expect(spy).toHaveBeenCalled() 59 }) 60 61 it('before', function () { 62 transition.beforeWithTransition(el, target, vm, spy) 63 expect(parent.firstChild).toBe(el) 64 expect(el.nextSibling).toBe(target) 65 expect(spy).toHaveBeenCalled() 66 }) 67 68 it('remove', function () { 69 transition.removeWithTransition(target, vm, spy) 70 expect(parent.childNodes.length).toBe(0) 71 expect(spy).toHaveBeenCalled() 72 }) 73 }) 74 75 describe('Skipping', function () { 76 var el, vm, op, cb 77 beforeEach(function () { 78 el = document.createElement('div') 79 el.textContent = 'hello' 80 op = jasmine.createSpy('transition skip op') 81 cb = jasmine.createSpy('transition skip cb') 82 vm = new Vue() 83 }) 84 85 it('skip el with no transition data', function () { 86 transition.applyTransition(el, 1, op, vm, cb) 87 expect(op).toHaveBeenCalled() 88 expect(cb).toHaveBeenCalled() 89 }) 90 91 it('skip vm still being compiled', function () { 92 el.__v_trans = new Transition(el, 'test', null, vm) 93 transition.applyTransition(el, 1, op, vm, cb) 94 expect(op).toHaveBeenCalled() 95 expect(cb).toHaveBeenCalled() 96 }) 97 98 it('skip vm with parent still being compiled', function () { 99 el.__v_trans = new Transition(el, 'test', null, vm) 100 var child = new Vue({ 101 el: el, 102 parent: vm 103 }) 104 expect(child._isCompiled).toBe(true) 105 transition.applyTransition(el, 1, op, child, cb) 106 expect(op).toHaveBeenCalled() 107 expect(cb).toHaveBeenCalled() 108 }) 109 110 it('skip when css transition is not supported', function () { 111 var e = _.transitionEndEvent 112 _.transitionEndEvent = null 113 el.__v_trans = new Transition(el, 'test', null, vm) 114 vm.$mount(el) 115 transition.applyTransition(el, 1, op, vm, cb) 116 expect(op).toHaveBeenCalled() 117 expect(cb).toHaveBeenCalled() 118 _.transitionEndEvent = e 119 }) 120 }) 121 122 describe('CSS transitions', function () { 123 var vm, el, op, cb, hooks 124 beforeEach(function () { 125 el = document.createElement('div') 126 el.textContent = 'hello' 127 vm = new Vue({ el: el }) 128 op = jasmine.createSpy('css op') 129 cb = jasmine.createSpy('css cb') 130 document.body.appendChild(el) 131 hooks = { 132 beforeEnter: jasmine.createSpy('beforeEnter'), 133 enter: jasmine.createSpy('enter'), 134 afterEnter: jasmine.createSpy('afterEnter'), 135 beforeLeave: jasmine.createSpy('beforeLeave'), 136 leave: jasmine.createSpy('leave'), 137 afterLeave: jasmine.createSpy('afterLeave') 138 } 139 // !IMPORTANT! 140 // this ensures we force a layout for every test. 141 /* eslint-disable no-unused-vars */ 142 var f = document.body.offsetHeight 143 /* eslint-enable no-unused-vars */ 144 }) 145 146 afterEach(function () { 147 document.body.removeChild(el) 148 }) 149 150 it('skip on 0s duration (execute right at next frame)', function (done) { 151 el.__v_trans = new Transition(el, 'test', hooks, vm) 152 el.style.transition = 153 el.style.WebkitTransition = 'opacity 0s ease' 154 transition.applyTransition(el, 1, op, vm, cb) 155 expect(hooks.beforeEnter).toHaveBeenCalled() 156 expect(hooks.enter).toHaveBeenCalled() 157 _.nextTick(function () { 158 expect(op).toHaveBeenCalled() 159 expect(cb).toHaveBeenCalled() 160 expect(hooks.afterEnter).toHaveBeenCalled() 161 expect(el.classList.contains('test-enter')).toBe(false) 162 transition.applyTransition(el, -1, op, vm, cb) 163 expect(hooks.beforeLeave).toHaveBeenCalled() 164 expect(hooks.leave).toHaveBeenCalled() 165 _.nextTick(function () { 166 expect(op.calls.count()).toBe(2) 167 expect(cb.calls.count()).toBe(2) 168 expect(hooks.afterLeave).toHaveBeenCalled() 169 expect(el.classList.contains('test-leave')).toBe(false) 170 done() 171 }) 172 }) 173 }) 174 175 it('skip when no transition available', function (done) { 176 el.__v_trans = new Transition(el, 'test-no-trans', hooks, vm) 177 transition.applyTransition(el, 1, op, vm, cb) 178 expect(hooks.beforeEnter).toHaveBeenCalled() 179 expect(hooks.enter).toHaveBeenCalled() 180 _.nextTick(function () { 181 expect(op).toHaveBeenCalled() 182 expect(cb).toHaveBeenCalled() 183 expect(hooks.afterEnter).toHaveBeenCalled() 184 expect(el.classList.contains('test-no-trans-enter')).toBe(false) 185 // wait until transition.justEntered flag is off 186 setTimeout(function () { 187 transition.applyTransition(el, -1, op, vm, cb) 188 expect(hooks.beforeLeave).toHaveBeenCalled() 189 expect(hooks.leave).toHaveBeenCalled() 190 _.nextTick(function () { 191 expect(op.calls.count()).toBe(2) 192 expect(cb.calls.count()).toBe(2) 193 expect(hooks.afterLeave).toHaveBeenCalled() 194 expect(el.classList.contains('test-no-trans-leave')).toBe(false) 195 done() 196 }) 197 }, 50) 198 }) 199 }) 200 201 it('transition enter', function (done) { 202 document.body.removeChild(el) 203 el.__v_trans = new Transition(el, 'test', hooks, vm) 204 // inline style 205 el.style.transition = 206 el.style.WebkitTransition = 'opacity ' + duration + 'ms ease' 207 transition.applyTransition(el, 1, function () { 208 document.body.appendChild(el) 209 op() 210 }, vm, cb) 211 expect(hooks.beforeEnter).toHaveBeenCalled() 212 expect(hooks.enter).toHaveBeenCalled() 213 expect(op).toHaveBeenCalled() 214 expect(cb).not.toHaveBeenCalled() 215 _.nextTick(function () { 216 expect(el.classList.contains('test-enter')).toBe(false) 217 expect(hooks.afterEnter).not.toHaveBeenCalled() 218 _.on(el, _.transitionEndEvent, function () { 219 expect(cb).toHaveBeenCalled() 220 expect(hooks.afterEnter).toHaveBeenCalled() 221 done() 222 }) 223 }) 224 }) 225 226 it('transition enter for svg', function (done) { 227 el.innerHTML = '<svg><circle cx="0" cy="0" r="10"></circle></svg>' 228 var svg = el.querySelector('svg') 229 var circle = el.querySelector('circle') 230 svg.removeChild(circle) 231 circle.__v_trans = new Transition(circle, 'test', hooks, vm) 232 // inline style 233 circle.style.transition = 234 circle.style.WebkitTransition = 'opacity ' + duration + 'ms ease' 235 transition.applyTransition(circle, 1, function () { 236 svg.appendChild(circle) 237 op() 238 }, vm, cb) 239 expect(hooks.beforeEnter).toHaveBeenCalled() 240 expect(hooks.enter).toHaveBeenCalled() 241 expect(op).toHaveBeenCalled() 242 expect(cb).not.toHaveBeenCalled() 243 _.nextTick(function () { 244 expect(circle.getAttribute('class').indexOf('test-enter') > -1).toBe(false) 245 expect(hooks.afterEnter).not.toHaveBeenCalled() 246 _.on(circle, _.transitionEndEvent, function () { 247 expect(cb).toHaveBeenCalled() 248 expect(hooks.afterEnter).toHaveBeenCalled() 249 done() 250 }) 251 }) 252 }) 253 254 it('transition leave', function (done) { 255 el.__v_trans = new Transition(el, 'test', hooks, vm) 256 // cascaded class style 257 el.classList.add('test') 258 // force a layout here so the transition can be triggered 259 /* eslint-disable no-unused-vars */ 260 var f = el.offsetHeight 261 /* eslint-enable no-unused-vars */ 262 transition.applyTransition(el, -1, op, vm, cb) 263 expect(hooks.beforeLeave).toHaveBeenCalled() 264 expect(hooks.leave).toHaveBeenCalled() 265 _.nextTick(function () { 266 expect(op).not.toHaveBeenCalled() 267 expect(cb).not.toHaveBeenCalled() 268 expect(hooks.afterLeave).not.toHaveBeenCalled() 269 expect(el.classList.contains('test-leave')).toBe(true) 270 _.on(el, _.transitionEndEvent, function () { 271 expect(op).toHaveBeenCalled() 272 expect(cb).toHaveBeenCalled() 273 expect(el.classList.contains('test-leave')).toBe(false) 274 expect(hooks.afterLeave).toHaveBeenCalled() 275 done() 276 }) 277 }) 278 }) 279 280 it('transition leave for svg', function (done) { 281 el.innerHTML = '<svg><circle cx="0" cy="0" r="10" class="test"></circle></svg>' 282 var circle = el.querySelector('circle') 283 circle.__v_trans = new Transition(circle, 'test', hooks, vm) 284 // force a layout here so the transition can be triggered 285 /* eslint-disable no-unused-vars */ 286 var f = el.offsetHeight 287 /* eslint-enable no-unused-vars */ 288 transition.applyTransition(circle, -1, op, vm, cb) 289 expect(hooks.beforeLeave).toHaveBeenCalled() 290 expect(hooks.leave).toHaveBeenCalled() 291 _.nextTick(function () { 292 expect(op).not.toHaveBeenCalled() 293 expect(cb).not.toHaveBeenCalled() 294 expect(hooks.afterLeave).not.toHaveBeenCalled() 295 expect(circle.getAttribute('class').indexOf('test-leave') > -1).toBe(true) 296 _.on(circle, _.transitionEndEvent, function () { 297 expect(op).toHaveBeenCalled() 298 expect(cb).toHaveBeenCalled() 299 expect(circle.getAttribute('class').indexOf('test-leave') > -1).toBe(false) 300 expect(hooks.afterLeave).toHaveBeenCalled() 301 done() 302 }) 303 }) 304 }) 305 306 it('animation enter', function (done) { 307 document.body.removeChild(el) 308 el.__v_trans = new Transition(el, 'test-anim', hooks, vm) 309 transition.applyTransition(el, 1, function () { 310 document.body.appendChild(el) 311 op() 312 }, vm, cb) 313 expect(hooks.beforeEnter).toHaveBeenCalled() 314 expect(hooks.enter).toHaveBeenCalled() 315 _.nextTick(function () { 316 expect(op).toHaveBeenCalled() 317 expect(cb).not.toHaveBeenCalled() 318 expect(el.classList.contains('test-anim-enter')).toBe(true) 319 expect(hooks.afterEnter).not.toHaveBeenCalled() 320 _.on(el, _.animationEndEvent, function () { 321 expect(el.classList.contains('test-anim-enter')).toBe(false) 322 expect(cb).toHaveBeenCalled() 323 expect(hooks.afterEnter).toHaveBeenCalled() 324 done() 325 }) 326 }) 327 }) 328 329 it('animation leave', function (done) { 330 el.__v_trans = new Transition(el, 'test-anim', hooks, vm) 331 transition.applyTransition(el, -1, op, vm, cb) 332 expect(hooks.beforeLeave).toHaveBeenCalled() 333 expect(hooks.leave).toHaveBeenCalled() 334 _.nextTick(function () { 335 expect(op).not.toHaveBeenCalled() 336 expect(cb).not.toHaveBeenCalled() 337 expect(el.classList.contains('test-anim-leave')).toBe(true) 338 expect(hooks.afterLeave).not.toHaveBeenCalled() 339 _.on(el, _.animationEndEvent, function () { 340 expect(op).toHaveBeenCalled() 341 expect(cb).toHaveBeenCalled() 342 expect(el.classList.contains('test-anim-leave')).toBe(false) 343 expect(hooks.afterLeave).toHaveBeenCalled() 344 done() 345 }) 346 }) 347 }) 348 349 it('css + js hook with callback', function (done) { 350 document.body.removeChild(el) 351 el.classList.add('test') 352 353 // enter hook that expects a second argument 354 // indicates the user wants to control when the 355 // transition ends. 356 var enterCalled = false 357 hooks.enter = function (el, enterDone) { 358 enterCalled = true 359 setTimeout(function () { 360 enterDone() 361 testDone() 362 }, duration * 1.5) 363 } 364 365 el.__v_trans = new Transition(el, 'test', hooks, vm) 366 transition.applyTransition(el, 1, function () { 367 document.body.appendChild(el) 368 op() 369 }, vm, cb) 370 expect(hooks.beforeEnter).toHaveBeenCalled() 371 expect(op).toHaveBeenCalled() 372 expect(cb).not.toHaveBeenCalled() 373 expect(enterCalled).toBe(true) 374 _.nextTick(function () { 375 expect(el.classList.contains('test-enter')).toBe(false) 376 expect(hooks.afterEnter).not.toHaveBeenCalled() 377 _.on(el, _.transitionEndEvent, function () { 378 // should wait until js callback is called! 379 expect(cb).not.toHaveBeenCalled() 380 expect(hooks.afterEnter).not.toHaveBeenCalled() 381 }) 382 }) 383 384 // this is called by the enter hook 385 function testDone () { 386 expect(cb).toHaveBeenCalled() 387 expect(hooks.afterEnter).toHaveBeenCalled() 388 done() 389 } 390 }) 391 392 it('css + js hook with callback before transitionend', function (done) { 393 document.body.removeChild(el) 394 el.classList.add('test') 395 396 // enter hook that expects a second argument 397 // indicates the user wants to control when the 398 // transition ends. 399 var enterCalled = false 400 hooks.enter = function (el, enterDone) { 401 enterCalled = true 402 setTimeout(function () { 403 enterDone() 404 testDone() 405 }, duration / 2) 406 } 407 408 el.__v_trans = new Transition(el, 'test', hooks, vm) 409 transition.applyTransition(el, 1, function () { 410 document.body.appendChild(el) 411 op() 412 }, vm, cb) 413 expect(hooks.beforeEnter).toHaveBeenCalled() 414 expect(op).toHaveBeenCalled() 415 expect(cb).not.toHaveBeenCalled() 416 expect(enterCalled).toBe(true) 417 _.nextTick(function () { 418 expect(el.classList.contains('test-enter')).toBe(false) 419 expect(hooks.afterEnter).not.toHaveBeenCalled() 420 _.on(el, _.transitionEndEvent, function () { 421 // callback should have been called, but only once, by the js callback 422 expect(cb).toHaveBeenCalled() 423 expect(cb.calls.count()).toBe(1) 424 expect(hooks.afterEnter).toHaveBeenCalled() 425 done() 426 }) 427 }) 428 429 // this is called by the enter hook 430 function testDone () { 431 expect(cb).toHaveBeenCalled() 432 expect(hooks.afterEnter).toHaveBeenCalled() 433 } 434 }) 435 436 it('clean up unfinished css callback', function (done) { 437 el.__v_trans = new Transition(el, 'test', null, vm) 438 el.classList.add('test') 439 transition.applyTransition(el, -1, function () { 440 document.body.removeChild(el) 441 }, vm, cb) 442 // cancel early 443 _.nextTick(function () { 444 expect(el.__v_trans.pendingCssCb).toBeTruthy() 445 expect(el.classList.contains('test-leave')).toBe(true) 446 transition.applyTransition(el, 1, function () { 447 document.body.appendChild(el) 448 }, vm) 449 expect(cb).not.toHaveBeenCalled() 450 expect(el.classList.contains('test-leave')).toBe(false) 451 expect(el.__v_trans.pendingCssCb).toBeNull() 452 // IMPORTANT 453 // Let the queue flush finish before enter the next 454 // test. Don't remove the nextTick. 455 _.nextTick(done) 456 }) 457 }) 458 459 it('cache transition sniff results', function (done) { 460 el.__v_trans = new Transition(el, 'test', null, vm) 461 el.classList.add('test') 462 transition.applyTransition(el, 1, op, vm) 463 _.nextTick(function () { 464 expect(el.__v_trans.typeCache['test-enter']).not.toBeUndefined() 465 // for some reason window.getComputedStyle cannot be spied on in 466 // phantomjs after the refactor... 467 var calls = 0 468 Object.defineProperty(el.__v_trans.typeCache, 'test-enter', { 469 get: function () { 470 calls++ 471 return 1 472 } 473 }) 474 transition.applyTransition(el, 1, op, vm) 475 _.nextTick(function () { 476 expect(calls).toBe(1) 477 done() 478 }) 479 }) 480 }) 481 }) 482 483 describe('JavaScript only transitions', function () { 484 var el, vm, op, cb, hooks 485 beforeEach(function () { 486 hooks = {} 487 el = document.createElement('div') 488 el.textContent = 'hello' 489 document.body.appendChild(el) 490 op = jasmine.createSpy('js transition op') 491 cb = jasmine.createSpy('js transition cb') 492 vm = new Vue({ el: el }) 493 }) 494 495 afterEach(function () { 496 document.body.removeChild(el) 497 }) 498 499 it('beforeEnter', function () { 500 var spy = jasmine.createSpy('js transition beforeEnter') 501 hooks.beforeEnter = function (el) { 502 spy(this, el) 503 } 504 el.__v_trans = new Transition(el, 'test', hooks, vm) 505 transition.applyTransition(el, 1, op, vm, cb) 506 expect(spy).toHaveBeenCalledWith(vm, el) 507 }) 508 509 it('enter', function () { 510 var spy = jasmine.createSpy('js enter') 511 hooks.enter = function (e, done) { 512 expect(e).toBe(el) 513 expect(op).toHaveBeenCalled() 514 done() 515 expect(cb).toHaveBeenCalled() 516 spy(this) 517 } 518 el.__v_trans = new Transition(el, 'test', hooks, vm) 519 transition.applyTransition(el, 1, op, vm, cb) 520 expect(spy).toHaveBeenCalledWith(vm) 521 }) 522 523 it('leave', function () { 524 var spy = jasmine.createSpy('js leave') 525 hooks.leave = function (e, done) { 526 expect(e).toBe(el) 527 done() 528 expect(op).toHaveBeenCalled() 529 expect(cb).toHaveBeenCalled() 530 spy(this) 531 } 532 el.__v_trans = new Transition(el, 'test', hooks, vm) 533 transition.applyTransition(el, -1, op, vm, cb) 534 expect(spy).toHaveBeenCalledWith(vm) 535 }) 536 537 it('no def', function (done) { 538 el.__v_trans = new Transition(el, 'test', null, vm) 539 transition.applyTransition(el, 1, op, vm, cb) 540 _.nextTick(function () { 541 expect(op).toHaveBeenCalled() 542 expect(cb).toHaveBeenCalled() 543 transition.applyTransition(el, -1, op, vm, cb) 544 _.nextTick(function () { 545 expect(op.calls.count()).toBe(2) 546 expect(cb.calls.count()).toBe(2) 547 done() 548 }) 549 }) 550 }) 551 552 it('cancel hook', function (done) { 553 var cleanupSpy = jasmine.createSpy('js cleanup') 554 var leaveSpy = jasmine.createSpy('js leave') 555 var timeout 556 hooks.enter = function (el, done) { 557 timeout = setTimeout(done, duration / 2) 558 } 559 hooks.enterCancelled = function () { 560 clearTimeout(timeout) 561 cleanupSpy() 562 } 563 hooks.leave = function (el, done) { 564 expect(cleanupSpy).toHaveBeenCalled() 565 leaveSpy() 566 done() 567 } 568 el.__v_trans = new Transition(el, 'test', hooks, vm) 569 transition.applyTransition(el, 1, op, vm, cb) 570 setTimeout(function () { 571 transition.applyTransition(el, -1, op, vm) 572 expect(leaveSpy).toHaveBeenCalled() 573 setTimeout(function () { 574 expect(cb).not.toHaveBeenCalled() 575 done() 576 }, duration / 2) 577 }, duration / 4) 578 }) 579 }) 580 }) 581 }