watcher.spec.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import Vue from 'vue'
  2. import Watcher from 'core/observer/watcher'
  3. describe('Watcher', () => {
  4. let vm, spy
  5. beforeEach(() => {
  6. vm = new Vue({
  7. template: '<div></div>',
  8. data: {
  9. a: 1,
  10. b: {
  11. c: 2,
  12. d: 4
  13. },
  14. c: 'c',
  15. msg: 'yo'
  16. }
  17. }).$mount()
  18. spy = jasmine.createSpy('watcher')
  19. })
  20. it('path', done => {
  21. const watcher = new Watcher(vm, 'b.c', spy)
  22. expect(watcher.value).toBe(2)
  23. vm.b.c = 3
  24. waitForUpdate(() => {
  25. expect(watcher.value).toBe(3)
  26. expect(spy).toHaveBeenCalledWith(3, 2)
  27. vm.b = { c: 4 } // swapping the object
  28. }).then(() => {
  29. expect(watcher.value).toBe(4)
  30. expect(spy).toHaveBeenCalledWith(4, 3)
  31. done()
  32. }).catch(done)
  33. })
  34. it('non-existent path, set later', done => {
  35. const watcher1 = new Watcher(vm, 'b.e', spy)
  36. expect(watcher1.value).toBeUndefined()
  37. // check $add should not affect isolated children
  38. const child2 = new Vue({ parent: vm })
  39. const watcher2 = new Watcher(child2, 'b.e', spy)
  40. expect(watcher2.value).toBeUndefined()
  41. Vue.set(vm.b, 'e', 123)
  42. waitForUpdate(() => {
  43. expect(watcher1.value).toBe(123)
  44. expect(watcher2.value).toBeUndefined()
  45. expect(spy.calls.count()).toBe(1)
  46. expect(spy).toHaveBeenCalledWith(123, undefined)
  47. done()
  48. }).catch(done)
  49. })
  50. it('delete', done => {
  51. const watcher = new Watcher(vm, 'b.c', spy)
  52. expect(watcher.value).toBe(2)
  53. Vue.delete(vm.b, 'c')
  54. waitForUpdate(() => {
  55. expect(watcher.value).toBeUndefined()
  56. expect(spy).toHaveBeenCalledWith(undefined, 2)
  57. done()
  58. }).catch(done)
  59. })
  60. it('swapping $data', done => {
  61. // existing path
  62. const watcher1 = new Watcher(vm, 'b.c', spy)
  63. // non-existing path
  64. const spy2 = jasmine.createSpy()
  65. const watcher2 = new Watcher(vm, 'e', spy2)
  66. expect(watcher1.value).toBe(2)
  67. expect(watcher2.value).toBeUndefined()
  68. vm.$data = { b: { c: 3 }, e: 4 }
  69. waitForUpdate(() => {
  70. expect(watcher1.value).toBe(2)
  71. expect(watcher2.value).toBeUndefined()
  72. expect(spy).not.toHaveBeenCalledWith(3, 2)
  73. expect(spy2).not.toHaveBeenCalledWith(4, undefined)
  74. done()
  75. }).catch(done)
  76. })
  77. it('path containing $data', done => {
  78. const watcher = new Watcher(vm, '$data.b.c', spy)
  79. expect(watcher.value).toBeUndefined()
  80. vm.b = { c: 3 }
  81. waitForUpdate(() => {
  82. expect(watcher.value).toBeUndefined()
  83. expect(spy).not.toHaveBeenCalledWith(3, 2)
  84. vm.$data = { b: { c: 4 }}
  85. }).then(() => {
  86. expect(watcher.value).toBeUndefined()
  87. expect(spy).not.toHaveBeenCalledWith(4, 3)
  88. done()
  89. }).catch(done)
  90. })
  91. it('not watching $data', done => {
  92. const oldData = vm.$data
  93. const watcher = new Watcher(vm, '$data', spy)
  94. expect(watcher.value).toBeUndefined()
  95. const newData = {}
  96. vm.$data = newData
  97. waitForUpdate(() => {
  98. expect(spy).not.toHaveBeenCalledWith(newData, oldData)
  99. expect(watcher.value).toBeUndefined()
  100. done()
  101. }).catch(done)
  102. })
  103. it('deep watch', done => {
  104. let oldB
  105. new Watcher(vm, 'b', spy, {
  106. deep: true
  107. })
  108. vm.b.c = { d: 4 }
  109. waitForUpdate(() => {
  110. expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
  111. oldB = vm.b
  112. vm.b = { c: [{ a: 1 }] }
  113. }).then(() => {
  114. expect(spy).toHaveBeenCalledWith(vm.b, oldB)
  115. expect(spy.calls.count()).toBe(2)
  116. vm.b.c[0].a = 2
  117. }).then(() => {
  118. expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
  119. expect(spy.calls.count()).toBe(3)
  120. done()
  121. }).catch(done)
  122. })
  123. it('deep watch with circular references', done => {
  124. new Watcher(vm, 'b', spy, {
  125. deep: true
  126. })
  127. Vue.set(vm.b, '_', vm.b)
  128. waitForUpdate(() => {
  129. expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
  130. expect(spy.calls.count()).toBe(1)
  131. vm.b._.c = 1
  132. }).then(() => {
  133. expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
  134. expect(spy.calls.count()).toBe(2)
  135. done()
  136. }).catch(done)
  137. })
  138. it('fire change for prop addition/deletion in non-deep mode', done => {
  139. new Watcher(vm, 'b', spy)
  140. Vue.set(vm.b, 'e', 123)
  141. waitForUpdate(() => {
  142. expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
  143. expect(spy.calls.count()).toBe(1)
  144. Vue.delete(vm.b, 'e')
  145. }).then(() => {
  146. expect(spy.calls.count()).toBe(2)
  147. done()
  148. }).catch(done)
  149. })
  150. it('watch function', done => {
  151. const watcher = new Watcher(vm, function () {
  152. return this.a + this.b.d
  153. }, spy)
  154. expect(watcher.value).toBe(5)
  155. vm.a = 2
  156. waitForUpdate(() => {
  157. expect(spy).toHaveBeenCalledWith(6, 5)
  158. vm.b = { d: 2 }
  159. }).then(() => {
  160. expect(spy).toHaveBeenCalledWith(4, 6)
  161. done()
  162. }).catch(done)
  163. })
  164. it('lazy mode', done => {
  165. const watcher = new Watcher(vm, function () {
  166. return this.a + this.b.d
  167. }, null, { lazy: true })
  168. expect(watcher.lazy).toBe(true)
  169. expect(watcher.value).toBeUndefined()
  170. expect(watcher.dirty).toBe(true)
  171. watcher.evaluate()
  172. expect(watcher.value).toBe(5)
  173. expect(watcher.dirty).toBe(false)
  174. vm.a = 2
  175. waitForUpdate(() => {
  176. expect(watcher.value).toBe(5)
  177. expect(watcher.dirty).toBe(true)
  178. watcher.evaluate()
  179. expect(watcher.value).toBe(6)
  180. expect(watcher.dirty).toBe(false)
  181. done()
  182. }).catch(done)
  183. })
  184. it('teardown', done => {
  185. const watcher = new Watcher(vm, 'b.c', spy)
  186. watcher.teardown()
  187. vm.b.c = 3
  188. waitForUpdate(() => {
  189. expect(watcher.active).toBe(false)
  190. expect(spy).not.toHaveBeenCalled()
  191. done()
  192. }).catch(done)
  193. })
  194. it('warn not support path', () => {
  195. new Watcher(vm, 'd.e + c', spy)
  196. expect('Failed watching path:').toHaveBeenWarned()
  197. })
  198. })