lifecycle_spec.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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._blockFragment).toBe(frag)
  90. expect(vm.$el.nextSibling.textContent).toBe('frag')
  91. })
  92. it('replace fragment', function () {
  93. document.body.appendChild(el)
  94. var vm = new Vue({
  95. replace: true,
  96. data: { test: 'hi!' },
  97. template: '<div>{{test}}</div><div>{{test + "!"}}</div>'
  98. })
  99. vm.$mount(el)
  100. expect(vm.$el).not.toBe(el)
  101. expect(vm.$el.nextSibling.textContent).toBe('hi!')
  102. expect(vm.$el.nextSibling.nextSibling.textContent).toBe('hi!!')
  103. expect(document.body.contains(el)).toBe(false)
  104. expect(document.body.lastChild).toBe(vm._blockEnd)
  105. vm.$remove()
  106. })
  107. it('hooks', function () {
  108. var hooks = ['created', 'beforeCompile', 'compiled', 'attached', 'ready']
  109. var options = {
  110. data: {
  111. test: 'hihi'
  112. }
  113. }
  114. hooks.forEach(function (hook) {
  115. options[hook] = jasmine.createSpy(hook)
  116. })
  117. var vm = new Vue(options)
  118. expect(options.created).toHaveBeenCalled()
  119. expect(options.beforeCompile).not.toHaveBeenCalled()
  120. vm.$mount(el)
  121. expect(options.beforeCompile).toHaveBeenCalled()
  122. expect(options.compiled).toHaveBeenCalled()
  123. expect(options.attached).not.toHaveBeenCalled()
  124. expect(options.ready).not.toHaveBeenCalled()
  125. vm.$appendTo(document.body)
  126. expect(options.attached).toHaveBeenCalled()
  127. expect(options.ready).toHaveBeenCalled()
  128. vm.$remove()
  129. })
  130. it('warn against multiple calls', function () {
  131. var vm = new Vue({
  132. el: el
  133. })
  134. vm.$mount(el)
  135. expect(_.warn).toHaveBeenCalled()
  136. })
  137. })
  138. describe('$destroy', function () {
  139. it('normal', function () {
  140. var vm = new Vue()
  141. expect(vm._isDestroyed).toBe(false)
  142. var data = vm._data
  143. expect(data.__ob__.vms.length).toBe(1)
  144. vm.$destroy()
  145. expect(data.__ob__.vms.length).toBe(0)
  146. expect(vm._isDestroyed).toBe(true)
  147. expect(vm._watchers).toBeNull()
  148. expect(vm._userWatchers).toBeNull()
  149. expect(vm._watcherList).toBeNull()
  150. expect(vm.$el).toBeNull()
  151. expect(vm.$parent).toBeNull()
  152. expect(vm.$root).toBeNull()
  153. expect(vm._children).toBeNull()
  154. expect(vm._directives).toBeNull()
  155. expect(Object.keys(vm._events).length).toBe(0)
  156. })
  157. it('remove element', function () {
  158. var el = document.createElement('div')
  159. var parent = document.createElement('div')
  160. parent.appendChild(el)
  161. var vm = new Vue({ el: el })
  162. vm.$destroy(true)
  163. expect(parent.childNodes.length).toBe(0)
  164. expect(el.__vue__).toBeNull()
  165. })
  166. it('hooks', function () {
  167. var opts = {
  168. beforeDestroy: jasmine.createSpy(),
  169. destroyed: jasmine.createSpy(),
  170. detached: jasmine.createSpy()
  171. }
  172. var el = opts.el = document.createElement('div')
  173. document.body.appendChild(el)
  174. var vm = new Vue(opts)
  175. vm.$destroy(true)
  176. expect(opts.beforeDestroy).toHaveBeenCalled()
  177. expect(opts.destroyed).toHaveBeenCalled()
  178. expect(opts.detached).toHaveBeenCalled()
  179. })
  180. it('parent', function () {
  181. var parent = new Vue()
  182. var child = parent.$addChild()
  183. var child2 = parent.$addChild()
  184. expect(parent._children.length).toBe(2)
  185. child.$destroy()
  186. expect(parent._children.length).toBe(1)
  187. child2.$destroy()
  188. expect(parent._children.length).toBe(0)
  189. })
  190. it('children', function () {
  191. var parent = new Vue()
  192. var child = parent.$addChild()
  193. parent.$destroy()
  194. expect(child._isDestroyed).toBe(true)
  195. })
  196. it('directives', function () {
  197. var spy = jasmine.createSpy('directive unbind')
  198. var vm = new Vue({
  199. el: document.createElement('div'),
  200. template: '<div v-test></div>',
  201. directives: {
  202. test: {
  203. unbind: spy
  204. }
  205. }
  206. })
  207. vm.$destroy()
  208. expect(spy).toHaveBeenCalled()
  209. })
  210. it('watchers', function () {
  211. var vm = new Vue({
  212. el: document.createElement('div'),
  213. template: '{{a}}',
  214. data: { a: 1 }
  215. })
  216. vm.$watch('a', function () {})
  217. var dirWatcher = vm._watcherList[0]
  218. var userWatcher = vm._watcherList[1]
  219. vm.$destroy()
  220. expect(dirWatcher.active).toBe(false)
  221. expect(userWatcher.active).toBe(false)
  222. })
  223. it('refuse multiple calls', function () {
  224. var spy = jasmine.createSpy()
  225. var vm = new Vue({
  226. beforeDestroy: spy
  227. })
  228. vm.$destroy()
  229. vm.$destroy()
  230. expect(spy.calls.count()).toBe(1)
  231. })
  232. it('safely teardown partial compilation', function () {
  233. var vm = new Vue({
  234. template: '<div v-component="dialog"><div v-partial="hello"></div></div>',
  235. partials: {
  236. hello: 'Hello {{name}}'
  237. },
  238. components: {
  239. dialog: {
  240. template: '<content>'
  241. }
  242. }
  243. }).$mount()
  244. expect(function () {
  245. vm.$destroy()
  246. }).not.toThrow()
  247. })
  248. })
  249. describe('$compile', function () {
  250. it('should partial compile and teardown stuff', function (done) {
  251. var el = document.createElement('div')
  252. var vm = new Vue({
  253. el: el,
  254. template: '{{a}}',
  255. data: {
  256. a: 'hi'
  257. }
  258. })
  259. expect(vm._directives.length).toBe(1)
  260. var partial = document.createElement('span')
  261. partial.textContent = '{{a}}'
  262. var decompile = vm.$compile(partial)
  263. expect(partial.textContent).toBe('hi')
  264. expect(vm._directives.length).toBe(2)
  265. decompile()
  266. expect(vm._directives.length).toBe(1)
  267. vm.a = 'ha'
  268. _.nextTick(function () {
  269. expect(el.textContent).toBe('ha')
  270. expect(partial.textContent).toBe('hi')
  271. done()
  272. })
  273. })
  274. })
  275. })
  276. }