watcher_spec.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. var Vue = require('../../../src/vue')
  2. var nextTick = Vue.nextTick
  3. var Watcher = require('../../../src/watcher')
  4. describe('Watcher', function () {
  5. var vm, spy
  6. beforeEach(function () {
  7. vm = new Vue({
  8. filters: {},
  9. data: {
  10. a: 1,
  11. b: {
  12. c: 2,
  13. d: 4
  14. },
  15. c: 'c'
  16. }
  17. })
  18. spy = jasmine.createSpy('watcher')
  19. })
  20. it('simple path', function (done) {
  21. var watcher = new Watcher(vm, 'b.c', spy)
  22. expect(watcher.value).toBe(2)
  23. vm.b.c = 3
  24. nextTick(function () {
  25. expect(watcher.value).toBe(3)
  26. expect(spy).toHaveBeenCalledWith(3, 2)
  27. vm.b = { c: 4 } // swapping the object
  28. nextTick(function () {
  29. expect(watcher.value).toBe(4)
  30. expect(spy).toHaveBeenCalledWith(4, 3)
  31. done()
  32. })
  33. })
  34. })
  35. it('bracket access path', function (done) {
  36. var watcher = new Watcher(vm, 'b["c"]', spy)
  37. expect(watcher.value).toBe(2)
  38. vm.b.c = 3
  39. nextTick(function () {
  40. expect(watcher.value).toBe(3)
  41. expect(spy).toHaveBeenCalledWith(3, 2)
  42. vm.b = { c: 4 } // swapping the object
  43. nextTick(function () {
  44. expect(watcher.value).toBe(4)
  45. expect(spy).toHaveBeenCalledWith(4, 3)
  46. done()
  47. })
  48. })
  49. })
  50. it('dynamic path', function (done) {
  51. var watcher = new Watcher(vm, 'b[c]', spy)
  52. expect(watcher.value).toBe(2)
  53. vm.b.c = 3
  54. nextTick(function () {
  55. expect(watcher.value).toBe(3)
  56. expect(spy).toHaveBeenCalledWith(3, 2)
  57. vm.c = 'd' // changing the dynamic segment in path
  58. nextTick(function () {
  59. expect(watcher.value).toBe(4)
  60. expect(spy).toHaveBeenCalledWith(4, 3)
  61. done()
  62. })
  63. })
  64. })
  65. it('simple expression', function (done) {
  66. var watcher = new Watcher(vm, 'a + b.c', spy)
  67. expect(watcher.value).toBe(3)
  68. vm.b.c = 3
  69. nextTick(function () {
  70. expect(watcher.value).toBe(4)
  71. expect(spy.calls.count()).toBe(1)
  72. expect(spy).toHaveBeenCalledWith(4, 3)
  73. // change two dependencies at once
  74. vm.a = 2
  75. vm.b.c = 4
  76. nextTick(function () {
  77. expect(watcher.value).toBe(6)
  78. // should trigger only once callback,
  79. // because it was in the same event loop.
  80. expect(spy.calls.count()).toBe(2)
  81. expect(spy).toHaveBeenCalledWith(6, 4)
  82. done()
  83. })
  84. })
  85. })
  86. it('ternary expression', function (done) {
  87. // we're actually testing for the dependency re-calculation here
  88. var watcher = new Watcher(vm, 'a > 1 ? b.c : b.d', spy)
  89. expect(watcher.value).toBe(4)
  90. vm.a = 2
  91. nextTick(function () {
  92. expect(watcher.value).toBe(2)
  93. expect(spy).toHaveBeenCalledWith(2, 4)
  94. vm.b.c = 3
  95. nextTick(function () {
  96. expect(watcher.value).toBe(3)
  97. expect(spy).toHaveBeenCalledWith(3, 2)
  98. done()
  99. })
  100. })
  101. })
  102. it('non-existent path, $add later', function (done) {
  103. var watcher = new Watcher(vm, 'd.e', spy)
  104. var watcher2 = new Watcher(vm, 'b.e', spy)
  105. expect(watcher.value).toBeUndefined()
  106. expect(watcher2.value).toBeUndefined()
  107. vm.$add('d', { e: 123 })
  108. vm.b.$add('e', 234)
  109. nextTick(function () {
  110. expect(watcher.value).toBe(123)
  111. expect(watcher2.value).toBe(234)
  112. expect(spy).toHaveBeenCalledWith(123, undefined)
  113. expect(spy).toHaveBeenCalledWith(234, undefined)
  114. done()
  115. })
  116. })
  117. it('$delete', function (done) {
  118. var watcher = new Watcher(vm, 'b.c', spy)
  119. expect(watcher.value).toBe(2)
  120. vm.$delete('b')
  121. nextTick(function () {
  122. expect(watcher.value).toBeUndefined()
  123. expect(spy).toHaveBeenCalledWith(undefined, 2)
  124. done()
  125. })
  126. })
  127. it('swapping $data', function (done) {
  128. var watcher = new Watcher(vm, 'b.c', spy)
  129. expect(watcher.value).toBe(2)
  130. vm.$data = { b: { c: 3}}
  131. nextTick(function () {
  132. expect(watcher.value).toBe(3)
  133. expect(spy).toHaveBeenCalledWith(3, 2)
  134. done()
  135. })
  136. })
  137. it('path containing $data', function (done) {
  138. var watcher = new Watcher(vm, '$data.b.c', spy)
  139. expect(watcher.value).toBe(2)
  140. vm.b = { c: 3 }
  141. nextTick(function () {
  142. expect(watcher.value).toBe(3)
  143. expect(spy).toHaveBeenCalledWith(3, 2)
  144. vm.$data = { b: {c: 4}}
  145. nextTick(function () {
  146. expect(watcher.value).toBe(4)
  147. expect(spy).toHaveBeenCalledWith(4, 3)
  148. done()
  149. })
  150. })
  151. })
  152. it('watching $data', function (done) {
  153. var oldData = vm.$data
  154. var watcher = new Watcher(vm, '$data', spy)
  155. expect(watcher.value).toBe(oldData)
  156. vm.a = 2
  157. nextTick(function () {
  158. expect(spy).toHaveBeenCalledWith(oldData, oldData)
  159. var newData = {}
  160. vm.$data = newData
  161. nextTick(function() {
  162. expect(spy).toHaveBeenCalledWith(newData, oldData)
  163. expect(watcher.value).toBe(newData)
  164. done()
  165. })
  166. })
  167. })
  168. it('watching parent scope properties', function (done) {
  169. var child = vm.$addChild()
  170. var spy2 = jasmine.createSpy('watch')
  171. var watcher1 = new Watcher(child, '$data', spy)
  172. var watcher2 = new Watcher(child, 'a', spy2)
  173. vm.a = 123
  174. nextTick(function () {
  175. // $data should only be called on self data change
  176. expect(watcher1.value).toBe(child.$data)
  177. expect(spy.calls.count()).toBe(0)
  178. expect(watcher2.value).toBe(123)
  179. expect(spy2).toHaveBeenCalledWith(123, 1)
  180. done()
  181. })
  182. })
  183. it('callback context', function (done) {
  184. var context = {}
  185. var watcher = new Watcher(vm, 'b.c', function () {
  186. spy.apply(this, arguments)
  187. expect(this).toBe(context)
  188. }, context)
  189. vm.b.c = 3
  190. nextTick(function () {
  191. expect(spy).toHaveBeenCalledWith(3, 2)
  192. done()
  193. })
  194. })
  195. it('filters', function (done) {
  196. vm.$options.filters.test = function (val, multi) {
  197. return val * multi
  198. }
  199. vm.$options.filters.test2 = function (val, str) {
  200. return val + str
  201. }
  202. var watcher = new Watcher(vm, 'b.c', spy, null, [
  203. { name: 'test', args: [3] },
  204. { name: 'test2', args: ['yo']}
  205. ])
  206. expect(watcher.value).toBe('6yo')
  207. vm.b.c = 3
  208. nextTick(function () {
  209. expect(watcher.value).toBe('9yo')
  210. expect(spy).toHaveBeenCalledWith('9yo', '6yo')
  211. done()
  212. })
  213. })
  214. it('setter', function (done) {
  215. vm.$options.filters.test = {
  216. write: function (val, oldVal, arg) {
  217. return val > arg ? val : oldVal
  218. }
  219. }
  220. var watcher = new Watcher(vm, 'b["c"]', spy, null, [
  221. { name: 'test', args: [5] }
  222. ], true)
  223. expect(watcher.value).toBe(2)
  224. watcher.set(4) // shoud not change the value
  225. nextTick(function () {
  226. expect(vm.b.c).toBe(2)
  227. expect(watcher.value).toBe(2)
  228. expect(spy.calls.count()).toBe(0)
  229. watcher.set(6)
  230. nextTick(function () {
  231. expect(vm.b.c).toBe(6)
  232. expect(watcher.value).toBe(6)
  233. expect(spy).toHaveBeenCalledWith(6, 2)
  234. done()
  235. })
  236. })
  237. })
  238. it('set non-existent values', function (done) {
  239. var watcher = new Watcher(vm, 'd.e.f', spy)
  240. expect(watcher.value).toBeUndefined()
  241. watcher.set(123)
  242. nextTick(function () {
  243. expect(vm.d.e.f).toBe(123)
  244. expect(watcher.value).toBe(123)
  245. expect(spy).toHaveBeenCalledWith(123, undefined)
  246. done()
  247. })
  248. })
  249. it('teardown', function (done) {
  250. var watcher = new Watcher(vm, 'b.c', spy)
  251. watcher.teardown()
  252. vm.b.c = 3
  253. nextTick(function () {
  254. expect(watcher.active).toBe(false)
  255. expect(spy.calls.count()).toBe(0)
  256. done()
  257. })
  258. })
  259. })