watcher.spec.js 5.5 KB

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