transition.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. describe('UNIT: Transition', function () {
  2. var transition = require('vue/src/transition'),
  3. config = require('vue/src/config'),
  4. codes = transition.codes,
  5. endEvent = sniffTransitionEndEvent(),
  6. enterClass = config.enterClass,
  7. leaveClass = config.leaveClass
  8. describe('General', function () {
  9. it('should skip if compiler is in init stage', function () {
  10. var c = mockChange(),
  11. compiler = mockCompiler()
  12. compiler.init = true
  13. var code = transition(null, 1, c.change, compiler)
  14. assert.ok(c.called)
  15. assert.strictEqual(code, codes.INIT)
  16. assert.ok(compiler.attached)
  17. })
  18. it('should skip if no transition is found on the node', function () {
  19. var c = mockChange(),
  20. compiler = mockCompiler(),
  21. code = transition(mockEl(), 1, c.change, compiler)
  22. assert.ok(c.called)
  23. assert.strictEqual(code, codes.SKIP)
  24. assert.ok(compiler.attached)
  25. })
  26. })
  27. describe('CSS class transition', function () {
  28. if (!endEvent) { // IE9 only test case
  29. it('should skip if transition is not available', function () {
  30. var c = mockChange(),
  31. compiler = mockCompiler(),
  32. code = transition(mockEl('css'), 1, c.change, compiler)
  33. assert.ok(c.called)
  34. assert.strictEqual(code, codes.CSS_SKIP)
  35. assert.ok(compiler.attached)
  36. })
  37. // skip the rest
  38. return
  39. }
  40. describe('enter', function () {
  41. var el = mockEl('css'),
  42. c = mockChange(function () {
  43. c.called = true
  44. assert.ok(el.classList.contains(enterClass))
  45. }),
  46. compiler = mockCompiler(),
  47. code,
  48. cbCalled = false
  49. el.vue_trans_cb = function () {
  50. cbCalled = true
  51. }
  52. el.addEventListener(endEvent, el.vue_trans_cb)
  53. it('should add the class before calling changeState()', function () {
  54. code = transition(el, 1, c.change, compiler)
  55. assert.ok(c.called)
  56. })
  57. it('should remove unfinished leave callback if exists', function () {
  58. assert.notOk(el.vue_trans_cb)
  59. var e = mockHTMLEvent(endEvent)
  60. el.dispatchEvent(e)
  61. assert.notOk(cbCalled)
  62. })
  63. it('should remove the v-leave class if the leave callback exists', function () {
  64. var el = mockEl('css')
  65. document.body.appendChild(el)
  66. el.style.width = '1px'
  67. code = transition(el, -1, function(){}, compiler)
  68. code = transition(el, 1, function(){}, compiler)
  69. assert.notOk(el.classList.contains(leaveClass))
  70. })
  71. it('should remove the class afterwards', function () {
  72. assert.notOk(el.classList.contains(enterClass))
  73. })
  74. it('should return correct code', function () {
  75. assert.strictEqual(code, codes.CSS_E)
  76. })
  77. it('should have called attached hook', function () {
  78. assert.ok(compiler.attached)
  79. })
  80. })
  81. describe('leave', function () {
  82. var el = mockEl('css'),
  83. c = mockChange(),
  84. compiler = mockCompiler(),
  85. code
  86. before(function () {
  87. document.body.appendChild(el)
  88. })
  89. it('should call change immediately if el is invisible', function () {
  90. var el = mockEl('css'),
  91. c = mockChange(),
  92. compiler = mockCompiler()
  93. code = transition(el, -1, c.change, compiler)
  94. assert.ok(c.called)
  95. assert.ok(compiler.detached)
  96. })
  97. it('should attach an ontransitionend listener', function () {
  98. el.style.width = '1px'
  99. code = transition(el, -1, c.change, compiler)
  100. assert.ok(typeof el.vue_trans_cb === 'function')
  101. })
  102. it('should add the class', function () {
  103. assert.ok(el.classList.contains(leaveClass))
  104. })
  105. it('should call changeState on transitionend', function () {
  106. var e = mockHTMLEvent(endEvent)
  107. el.dispatchEvent(e)
  108. assert.ok(c.called)
  109. })
  110. it('should remove the callback after called', function () {
  111. assert.notOk(el.vue_trans_cb)
  112. var e = mockHTMLEvent(endEvent)
  113. el.dispatchEvent(e)
  114. assert.strictEqual(c.n, 1)
  115. })
  116. it('should remove the class after called', function () {
  117. assert.notOk(el.classList.contains(leaveClass))
  118. })
  119. it('should return correct code', function () {
  120. assert.strictEqual(code, codes.CSS_L)
  121. })
  122. it('should have called detached hook', function () {
  123. assert.ok(compiler.detached)
  124. })
  125. })
  126. })
  127. describe('JavaScript transition', function () {
  128. it('should skip if correspinding option is not defined', function () {
  129. var c = mockChange(),
  130. compiler = mockCompiler(),
  131. code = transition(mockEl('js'), 1, c.change, compiler)
  132. assert.ok(c.called)
  133. assert.strictEqual(code, codes.JS_SKIP)
  134. assert.ok(compiler.attached)
  135. })
  136. it('should skip if the option is given but the enter/leave func is not defined', function () {
  137. var c = mockChange(),
  138. compiler = mockCompiler({}),
  139. code = transition(mockEl('js'), 1, c.change, compiler)
  140. assert.ok(c.called)
  141. assert.strictEqual(code, codes.JS_SKIP_E)
  142. assert.ok(compiler.attached)
  143. c = mockChange()
  144. compiler = mockCompiler({})
  145. code = transition(mockEl('js'), -1, c.change, compiler)
  146. assert.ok(c.called)
  147. assert.strictEqual(code, codes.JS_SKIP_L)
  148. assert.ok(compiler.detached)
  149. })
  150. describe('enter', function () {
  151. var code,
  152. c = mockChange(),
  153. el = mockEl('js'),
  154. def = {
  155. enter: function (element, change) {
  156. assert.strictEqual(el, element)
  157. change()
  158. }
  159. },
  160. compiler = mockCompiler(def)
  161. it('should call the enter function', function () {
  162. code = transition(el, 1, c.change, compiler)
  163. assert.ok(c.called)
  164. })
  165. it('should return correct code', function () {
  166. assert.strictEqual(code, codes.JS_E)
  167. })
  168. it('should have called attached hook', function () {
  169. assert.ok(compiler.attached)
  170. })
  171. })
  172. describe('leave', function () {
  173. var code,
  174. c = mockChange(),
  175. el = mockEl('js'),
  176. def = {
  177. leave: function (element, change) {
  178. assert.strictEqual(el, element)
  179. change()
  180. }
  181. },
  182. compiler = mockCompiler(def)
  183. it('should call the leave function', function () {
  184. code = transition(el, -1, c.change, compiler)
  185. assert.ok(c.called)
  186. })
  187. it('should return correct code', function () {
  188. assert.strictEqual(code, codes.JS_L)
  189. })
  190. it('should have called detached hook', function () {
  191. assert.ok(compiler.detached)
  192. })
  193. })
  194. })
  195. function mockChange (change) {
  196. var c = {
  197. called: false,
  198. n: 0,
  199. change: change || function () {
  200. c.called = true
  201. c.n += 1
  202. }
  203. }
  204. return c
  205. }
  206. function mockEl (type) {
  207. var el = document.createElement('div')
  208. if (type === 'css') {
  209. el.vue_trans = ''
  210. } else if (type === 'js') {
  211. el.vue_trans = 'test'
  212. }
  213. return el
  214. }
  215. function mockCompiler (opt) {
  216. return {
  217. getOption: function () {
  218. return opt
  219. },
  220. execHook: function (hook) {
  221. this[hook] = true
  222. }
  223. }
  224. }
  225. function sniffTransitionEndEvent () {
  226. var el = document.createElement('vue'),
  227. defaultEvent = 'transitionend',
  228. events = {
  229. 'transition' : defaultEvent,
  230. 'MozTransition' : defaultEvent,
  231. 'WebkitTransition' : 'webkitTransitionEnd'
  232. }
  233. for (var name in events) {
  234. if (el.style[name] !== undefined) {
  235. return events[name]
  236. }
  237. }
  238. }
  239. })