lifecycle_spec.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. var Vue = require('../../../../src/vue')
  2. var _ = require('../../../../src/util')
  3. var compile = require('../../../../src/compiler/compile')
  4. if (_.inBrowser) {
  5. describe('Lifecycle API', function () {
  6. describe('$mount', function () {
  7. var el, frag
  8. beforeEach(function () {
  9. el = document.createElement('div')
  10. el.textContent = '{{test}}'
  11. frag = document.createDocumentFragment()
  12. frag.appendChild(el)
  13. spyOn(_, 'warn')
  14. })
  15. it('normal', function () {
  16. var vm = new Vue({
  17. data: {
  18. test: 'hi!'
  19. }
  20. })
  21. vm.$mount(el)
  22. expect(vm.$el).toBe(el)
  23. expect(el.__vue__).toBe(vm)
  24. expect(el.textContent).toBe('hi!')
  25. })
  26. it('auto-create', function () {
  27. var vm = new Vue({
  28. template: '{{a}}',
  29. data: {
  30. a: 123
  31. }
  32. })
  33. vm.$mount()
  34. expect(vm.$el).toBeTruthy()
  35. expect(vm.$el.tagName).toBe('DIV')
  36. expect(vm.$el.textContent).toBe('123')
  37. })
  38. it('selector', function () {
  39. el.id = 'mount-test'
  40. document.body.appendChild(el)
  41. var vm = new Vue({
  42. data: { test: 'hi!' }
  43. })
  44. vm.$mount('#mount-test')
  45. expect(vm.$el).toBe(el)
  46. expect(el.__vue__).toBe(vm)
  47. expect(el.textContent).toBe('hi!')
  48. document.body.removeChild(el)
  49. })
  50. it('warn invalid selector', function () {
  51. var vm = new Vue()
  52. vm.$mount('#none-exist')
  53. expect(_.warn).toHaveBeenCalled()
  54. })
  55. it('replace', function () {
  56. el.className = 'replace-test'
  57. document.body.appendChild(el)
  58. var vm = new Vue({
  59. replace: true,
  60. data: { test: 'hi!' },
  61. template: '<div>{{test}}</div>'
  62. })
  63. vm.$mount(el)
  64. expect(vm.$el).not.toBe(el)
  65. expect(vm.$el.textContent).toBe('hi!')
  66. expect(document.body.contains(el)).toBe(false)
  67. expect(document.body.lastChild).toBe(vm.$el)
  68. expect(vm.$el.className).toBe('replace-test')
  69. document.body.removeChild(vm.$el)
  70. })
  71. it('precompiled linker', function () {
  72. var linker = compile(el, Vue.options)
  73. var vm = new Vue({
  74. _linker: linker,
  75. data: {
  76. test: 'hi!'
  77. }
  78. })
  79. vm.$mount(el)
  80. expect(vm.$el).toBe(el)
  81. expect(el.__vue__).toBe(vm)
  82. expect(el.textContent).toBe('hi!')
  83. })
  84. it('mount to fragment', function () {
  85. var vm = new Vue({
  86. data: { test: 'frag' }
  87. })
  88. vm.$mount(frag)
  89. expect(vm.$el).toBe(vm._blockStart)
  90. expect(vm._blockFragment).toBe(frag)
  91. expect(vm.$el.nextSibling.textContent).toBe('frag')
  92. })
  93. it('replace fragment', function () {
  94. document.body.appendChild(el)
  95. var vm = new Vue({
  96. replace: true,
  97. data: { test: 'hi!' },
  98. template: '<div>{{test}}</div><div>{{test}}</div>'
  99. })
  100. vm.$mount(el)
  101. expect(vm.$el.nextSibling).not.toBe(el)
  102. expect(vm.$el.nextSibling.textContent).toBe('hi!')
  103. expect(vm.$el.nextSibling.nextSibling.textContent).toBe('hi!')
  104. expect(document.body.contains(el)).toBe(false)
  105. expect(document.body.lastChild).toBe(vm._blockEnd)
  106. vm.$remove()
  107. })
  108. it('hooks', function () {
  109. var hooks = ['created', 'beforeCompile', 'compiled', 'attached', 'ready']
  110. var options = {
  111. data: {
  112. test: 'hihi'
  113. }
  114. }
  115. hooks.forEach(function (hook) {
  116. options[hook] = jasmine.createSpy(hook)
  117. })
  118. var vm = new Vue(options)
  119. expect(options.created).toHaveBeenCalled()
  120. expect(options.beforeCompile).not.toHaveBeenCalled()
  121. vm.$mount(el)
  122. expect(options.beforeCompile).toHaveBeenCalled()
  123. expect(options.compiled).toHaveBeenCalled()
  124. expect(options.attached).not.toHaveBeenCalled()
  125. expect(options.ready).not.toHaveBeenCalled()
  126. vm.$appendTo(document.body)
  127. expect(options.attached).toHaveBeenCalled()
  128. expect(options.ready).toHaveBeenCalled()
  129. vm.$remove()
  130. })
  131. it('warn against multiple calls', function () {
  132. var vm = new Vue({
  133. el: el
  134. })
  135. vm.$mount(el)
  136. expect(_.warn).toHaveBeenCalled()
  137. })
  138. })
  139. describe('$destroy', function () {
  140. it('normal', function () {
  141. var vm = new Vue()
  142. expect(vm._isDestroyed).toBe(false)
  143. var data = vm._data
  144. expect(data.__ob__.vms.length).toBe(1)
  145. vm.$destroy()
  146. expect(data.__ob__.vms.length).toBe(0)
  147. expect(vm._isDestroyed).toBe(true)
  148. expect(vm._watchers).toBeNull()
  149. expect(vm._userWatchers).toBeNull()
  150. expect(vm._watcherList).toBeNull()
  151. expect(vm.$el).toBeNull()
  152. expect(vm.$parent).toBeNull()
  153. expect(vm.$root).toBeNull()
  154. expect(vm._children).toBeNull()
  155. expect(vm._directives).toBeNull()
  156. expect(Object.keys(vm._events).length).toBe(0)
  157. })
  158. it('remove element', function () {
  159. var el = document.createElement('div')
  160. var parent = document.createElement('div')
  161. parent.appendChild(el)
  162. var vm = new Vue({ el: el })
  163. vm.$destroy(true)
  164. expect(parent.childNodes.length).toBe(0)
  165. expect(el.__vue__).toBeNull()
  166. })
  167. it('hooks', function () {
  168. var opts = {
  169. beforeDestroy: jasmine.createSpy(),
  170. destroyed: jasmine.createSpy(),
  171. detached: jasmine.createSpy()
  172. }
  173. var el = opts.el = document.createElement('div')
  174. document.body.appendChild(el)
  175. var vm = new Vue(opts)
  176. vm.$destroy(true)
  177. expect(opts.beforeDestroy).toHaveBeenCalled()
  178. expect(opts.destroyed).toHaveBeenCalled()
  179. expect(opts.detached).toHaveBeenCalled()
  180. })
  181. it('parent', function () {
  182. var parent = new Vue()
  183. var child = parent.$addChild()
  184. var child2 = parent.$addChild()
  185. expect(parent._children.length).toBe(2)
  186. child.$destroy()
  187. expect(parent._children.length).toBe(1)
  188. child2.$destroy()
  189. expect(parent._children.length).toBe(0)
  190. })
  191. it('children', function () {
  192. var parent = new Vue()
  193. var child = parent.$addChild()
  194. parent.$destroy()
  195. expect(child._isDestroyed).toBe(true)
  196. })
  197. it('directives', function () {
  198. var spy = jasmine.createSpy('directive unbind')
  199. var vm = new Vue({
  200. el: document.createElement('div'),
  201. template: '<div v-test></div>',
  202. directives: {
  203. test: {
  204. unbind: spy
  205. }
  206. }
  207. })
  208. vm.$destroy()
  209. expect(spy).toHaveBeenCalled()
  210. })
  211. it('watchers', function () {
  212. var vm = new Vue({
  213. el: document.createElement('div'),
  214. template: '{{a}}',
  215. data: { a: 1 }
  216. })
  217. vm.$watch('a', function () {})
  218. var dirWatcher = vm._watcherList[0]
  219. var userWatcher = vm._watcherList[1]
  220. vm.$destroy()
  221. expect(dirWatcher.active).toBe(false)
  222. expect(userWatcher.active).toBe(false)
  223. })
  224. it('refuse multiple calls', function () {
  225. var spy = jasmine.createSpy()
  226. var vm = new Vue({
  227. beforeDestroy: spy
  228. })
  229. vm.$destroy()
  230. vm.$destroy()
  231. expect(spy.calls.count()).toBe(1)
  232. })
  233. it('safely teardown partial compilation', function () {
  234. var vm = new Vue({
  235. template: '<div v-component="dialog"><div v-partial="hello"></div></div>',
  236. partials: {
  237. hello: 'Hello {{name}}'
  238. },
  239. components: {
  240. dialog: {
  241. template: '<content>'
  242. }
  243. }
  244. }).$mount()
  245. expect(function () {
  246. vm.$destroy()
  247. }).not.toThrow()
  248. })
  249. })
  250. describe('$compile', function () {
  251. it('should partial compile and teardown stuff', function (done) {
  252. var el = document.createElement('div')
  253. var vm = new Vue({
  254. el: el,
  255. template: '{{a}}',
  256. data: {
  257. a: 'hi'
  258. }
  259. })
  260. expect(vm._directives.length).toBe(1)
  261. var partial = document.createElement('span')
  262. partial.textContent = '{{a}}'
  263. var decompile = vm.$compile(partial)
  264. expect(partial.textContent).toBe('hi')
  265. expect(vm._directives.length).toBe(2)
  266. decompile()
  267. expect(vm._directives.length).toBe(1)
  268. vm.a = 'ha'
  269. _.nextTick(function () {
  270. expect(el.textContent).toBe('ha')
  271. expect(partial.textContent).toBe('hi')
  272. done()
  273. })
  274. })
  275. })
  276. })
  277. }