observer_spec.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. var Observer = require('../../../src/observer')
  2. var _ = require('../../../src/util')
  3. describe('Observer', function () {
  4. var spy
  5. beforeEach(function () {
  6. spy = jasmine.createSpy('observer')
  7. })
  8. it('create on non-observables', function () {
  9. // skip primitive value
  10. var ob = Observer.create(1)
  11. expect(ob).toBeUndefined()
  12. // avoid vue instance
  13. ob = Observer.create(new _.Vue())
  14. expect(ob).toBeUndefined()
  15. })
  16. it('create on object', function () {
  17. // on object
  18. var obj = {
  19. a: {},
  20. b: {}
  21. }
  22. var ob = Observer.create(obj)
  23. expect(ob instanceof Observer).toBe(true)
  24. expect(ob.active).toBe(true)
  25. expect(ob.value).toBe(obj)
  26. expect(obj.__ob__).toBe(ob)
  27. // should've walked children
  28. expect(obj.a.__ob__ instanceof Observer).toBe(true)
  29. expect(obj.b.__ob__ instanceof Observer).toBe(true)
  30. // should return existing ob on already observed objects
  31. var ob2 = Observer.create(obj)
  32. expect(ob2).toBe(ob)
  33. })
  34. it('create on array', function () {
  35. // on object
  36. var arr = [{}, {}]
  37. var ob = Observer.create(arr)
  38. expect(ob instanceof Observer).toBe(true)
  39. expect(ob.active).toBe(true)
  40. expect(ob.value).toBe(arr)
  41. expect(arr.__ob__).toBe(ob)
  42. // should've walked children
  43. expect(arr[0].__ob__ instanceof Observer).toBe(true)
  44. expect(arr[1].__ob__ instanceof Observer).toBe(true)
  45. })
  46. it('observing object prop change', function () {
  47. var obj = { a: { b: 2 } }
  48. Observer.create(obj)
  49. // mock a watcher!
  50. var watcher = {
  51. deps: [],
  52. addDep: function (binding) {
  53. this.deps.push(binding)
  54. binding.addSub(this)
  55. },
  56. update: jasmine.createSpy()
  57. }
  58. var dump
  59. // collect dep
  60. Observer.target = watcher
  61. dump = obj.a.b
  62. Observer.target = null
  63. expect(watcher.deps.length).toBe(2)
  64. dump = obj.a.b = 3
  65. expect(watcher.update.calls.count()).toBe(1)
  66. // swap object
  67. obj.a = { b: 4 }
  68. expect(watcher.update.calls.count()).toBe(2)
  69. // recollect dep
  70. var oldDeps = watcher.deps
  71. watcher.deps = []
  72. Observer.target = watcher
  73. dump = obj.a.b
  74. Observer.target = null
  75. expect(watcher.deps.length).toBe(2)
  76. // make sure we picked up the new bindings
  77. expect(watcher.deps[0]).not.toBe(oldDeps[0])
  78. expect(watcher.deps[1]).not.toBe(oldDeps[1])
  79. // set on the swapped object
  80. obj.a.b = 5
  81. expect(watcher.update.calls.count()).toBe(3)
  82. })
  83. it('observing $add/$delete', function () {
  84. var obj = { a: 1 }
  85. var ob = Observer.create(obj)
  86. var binding = ob.binding
  87. spyOn(binding, 'notify')
  88. obj.$add('b', 2)
  89. expect(obj.b).toBe(2)
  90. expect(binding.notify.calls.count()).toBe(1)
  91. obj.$delete('a')
  92. expect(obj.hasOwnProperty('a')).toBe(false)
  93. expect(binding.notify.calls.count()).toBe(2)
  94. // should ignore adding an existing key
  95. obj.$add('b', 3)
  96. expect(obj.b).toBe(2)
  97. expect(binding.notify.calls.count()).toBe(2)
  98. // should ignore deleting non-existing key
  99. obj.$delete('a')
  100. expect(binding.notify.calls.count()).toBe(2)
  101. })
  102. it('observing array mutation', function () {
  103. var arr = []
  104. var ob = Observer.create(arr)
  105. var binding = ob.binding
  106. spyOn(binding, 'notify')
  107. var objs = [{}, {}, {}]
  108. arr.push(objs[0])
  109. arr.pop()
  110. arr.unshift(objs[1])
  111. arr.shift()
  112. arr.splice(0, 0, objs[2])
  113. arr.sort()
  114. arr.reverse()
  115. expect(binding.notify.calls.count()).toBe(7)
  116. // inserted elements should be observed
  117. objs.forEach(function (obj) {
  118. expect(obj.__ob__ instanceof Observer).toBe(true)
  119. })
  120. })
  121. it('array $set', function () {
  122. var arr = [1]
  123. var ob = Observer.create(arr)
  124. var binding = ob.binding
  125. spyOn(binding, 'notify')
  126. arr.$set(0, 2)
  127. expect(arr[0]).toBe(2)
  128. expect(binding.notify.calls.count()).toBe(1)
  129. // setting out of bound index
  130. arr.$set(2, 3)
  131. expect(arr[2]).toBe(3)
  132. expect(binding.notify.calls.count()).toBe(2)
  133. })
  134. it('array $remove', function () {
  135. var arr = [{}, {}]
  136. var obj1 = arr[0]
  137. var obj2 = arr[1]
  138. var ob = Observer.create(arr)
  139. var binding = ob.binding
  140. spyOn(binding, 'notify')
  141. // remove by index
  142. arr.$remove(0)
  143. expect(arr.length).toBe(1)
  144. expect(arr[0]).toBe(obj2)
  145. expect(binding.notify.calls.count()).toBe(1)
  146. // remove by identity, not in array
  147. arr.$remove(obj1)
  148. expect(arr.length).toBe(1)
  149. expect(arr[0]).toBe(obj2)
  150. expect(binding.notify.calls.count()).toBe(1)
  151. // remove by identity, in array
  152. arr.$remove(obj2)
  153. expect(arr.length).toBe(0)
  154. expect(binding.notify.calls.count()).toBe(2)
  155. })
  156. })