observer_spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /**
  2. * Test data observation.
  3. */
  4. var Observer = require('../../../src/observe/observer')
  5. var _ = require('../../../src/util')
  6. Observer.pathDelimiter = '.'
  7. describe('Observer', function () {
  8. var spy
  9. beforeEach(function () {
  10. spy = jasmine.createSpy('observer')
  11. })
  12. it('get', function () {
  13. Observer.emitGet = true
  14. var obj = {
  15. a: 1,
  16. b: {
  17. c: 2
  18. }
  19. }
  20. var ob = Observer.create(obj)
  21. ob.on('get', spy)
  22. var t = obj.a
  23. expect(spy).toHaveBeenCalledWith('a', undefined, undefined)
  24. expect(spy.calls.count()).toBe(1)
  25. t = obj.b.c
  26. expect(spy).toHaveBeenCalledWith('b', undefined, undefined)
  27. expect(spy).toHaveBeenCalledWith('b.c', undefined, undefined)
  28. expect(spy.calls.count()).toBe(3)
  29. Observer.emitGet = false
  30. })
  31. it('set', function () {
  32. var obj = {
  33. a: 1,
  34. b: {
  35. c: 2
  36. }
  37. }
  38. var ob = Observer.create(obj)
  39. ob.on('set', spy)
  40. obj.a = 3
  41. expect(spy).toHaveBeenCalledWith('a', 3, undefined)
  42. expect(spy.calls.count()).toBe(1)
  43. obj.b.c = 4
  44. expect(spy).toHaveBeenCalledWith('b.c', 4, undefined)
  45. expect(spy.calls.count()).toBe(2)
  46. // swap set
  47. var newB = { c: 5 }
  48. obj.b = newB
  49. expect(spy).toHaveBeenCalledWith('b', newB, undefined)
  50. expect(spy.calls.count()).toBe(3)
  51. // same value set should not emit events
  52. obj.a = 3
  53. expect(spy.calls.count()).toBe(3)
  54. })
  55. it('ignore prefix', function () {
  56. var obj = {
  57. _test: 123,
  58. $test: 234
  59. }
  60. var ob = Observer.create(obj)
  61. ob.on('set', spy)
  62. obj._test = 234
  63. obj.$test = 345
  64. expect(spy.calls.count()).toBe(0)
  65. })
  66. it('ignore accessors', function () {
  67. var obj = {
  68. a: 123,
  69. get b () {
  70. return this.a
  71. }
  72. }
  73. var ob = Observer.create(obj)
  74. obj.a = 234
  75. expect(obj.b).toBe(234)
  76. })
  77. it('warn duplicate value', function () {
  78. spyOn(_, 'warn')
  79. var obj = {
  80. a: { b: 123 },
  81. b: null
  82. }
  83. var ob = Observer.create(obj)
  84. obj.b = obj.a
  85. expect(_.warn).toHaveBeenCalled()
  86. })
  87. it('array get', function () {
  88. Observer.emitGet = true
  89. var obj = {
  90. arr: [{a:1}, {a:2}]
  91. }
  92. var ob = Observer.create(obj)
  93. ob.on('get', spy)
  94. var t = obj.arr[0].a
  95. expect(spy).toHaveBeenCalledWith('arr', undefined, undefined)
  96. expect(spy).toHaveBeenCalledWith('arr.0.a', undefined, undefined)
  97. expect(spy.calls.count()).toBe(2)
  98. Observer.emitGet = false
  99. })
  100. it('array set', function () {
  101. var obj = {
  102. arr: [{a:1}, {a:2}]
  103. }
  104. var ob = Observer.create(obj)
  105. ob.on('set', spy)
  106. obj.arr[0].a = 2
  107. expect(spy).toHaveBeenCalledWith('arr.0.a', 2, undefined)
  108. // set events after mutation
  109. obj.arr.reverse()
  110. obj.arr[0].a = 3
  111. expect(spy).toHaveBeenCalledWith('arr.0.a', 3, undefined)
  112. })
  113. it('array push', function () {
  114. var arr = [{a:1}, {a:2}]
  115. var ob = Observer.create(arr)
  116. ob.on('mutate', spy)
  117. arr.push({a:3})
  118. expect(spy.calls.mostRecent().args[0]).toBe('')
  119. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  120. var mutation = spy.calls.mostRecent().args[2]
  121. expect(mutation).toBeDefined()
  122. expect(mutation.method).toBe('push')
  123. expect(mutation.index).toBe(2)
  124. expect(mutation.removed.length).toBe(0)
  125. expect(mutation.inserted.length).toBe(1)
  126. expect(mutation.inserted[0]).toBe(arr[2])
  127. // test index update after mutation
  128. ob.on('set', spy)
  129. arr[2].a = 4
  130. expect(spy).toHaveBeenCalledWith('2.a', 4, undefined)
  131. })
  132. it('array pop', function () {
  133. var arr = [{a:1}, {a:2}]
  134. var popped = arr[1]
  135. var ob = Observer.create(arr)
  136. ob.on('mutate', spy)
  137. arr.pop()
  138. expect(spy.calls.mostRecent().args[0]).toBe('')
  139. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  140. var mutation = spy.calls.mostRecent().args[2]
  141. expect(mutation).toBeDefined()
  142. expect(mutation.method).toBe('pop')
  143. expect(mutation.index).toBe(1)
  144. expect(mutation.inserted.length).toBe(0)
  145. expect(mutation.removed.length).toBe(1)
  146. expect(mutation.removed[0]).toBe(popped)
  147. })
  148. it('array shift', function () {
  149. var arr = [{a:1}, {a:2}]
  150. var shifted = arr[0]
  151. var ob = Observer.create(arr)
  152. ob.on('mutate', spy)
  153. arr.shift()
  154. expect(spy.calls.mostRecent().args[0]).toBe('')
  155. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  156. var mutation = spy.calls.mostRecent().args[2]
  157. expect(mutation).toBeDefined()
  158. expect(mutation.method).toBe('shift')
  159. expect(mutation.index).toBe(0)
  160. expect(mutation.inserted.length).toBe(0)
  161. expect(mutation.removed.length).toBe(1)
  162. expect(mutation.removed[0]).toBe(shifted)
  163. // test index update after mutation
  164. ob.on('set', spy)
  165. arr[0].a = 4
  166. expect(spy).toHaveBeenCalledWith('0.a', 4, undefined)
  167. })
  168. it('array unshift', function () {
  169. var arr = [{a:1}, {a:2}]
  170. var unshifted = {a:3}
  171. var ob = Observer.create(arr)
  172. ob.on('mutate', spy)
  173. arr.unshift(unshifted)
  174. expect(spy.calls.mostRecent().args[0]).toBe('')
  175. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  176. var mutation = spy.calls.mostRecent().args[2]
  177. expect(mutation).toBeDefined()
  178. expect(mutation.method).toBe('unshift')
  179. expect(mutation.index).toBe(0)
  180. expect(mutation.removed.length).toBe(0)
  181. expect(mutation.inserted.length).toBe(1)
  182. expect(mutation.inserted[0]).toBe(unshifted)
  183. // test index update after mutation
  184. ob.on('set', spy)
  185. arr[1].a = 4
  186. expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
  187. })
  188. it('array splice', function () {
  189. var arr = [{a:1}, {a:2}]
  190. var inserted = {a:3}
  191. var removed = arr[1]
  192. var ob = Observer.create(arr)
  193. ob.on('mutate', spy)
  194. arr.splice(1, 1, inserted)
  195. expect(spy.calls.mostRecent().args[0]).toBe('')
  196. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  197. var mutation = spy.calls.mostRecent().args[2]
  198. expect(mutation).toBeDefined()
  199. expect(mutation.method).toBe('splice')
  200. expect(mutation.index).toBe(1)
  201. expect(mutation.removed.length).toBe(1)
  202. expect(mutation.inserted.length).toBe(1)
  203. expect(mutation.removed[0]).toBe(removed)
  204. expect(mutation.inserted[0]).toBe(inserted)
  205. // test index update after mutation
  206. ob.on('set', spy)
  207. arr[1].a = 4
  208. expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
  209. })
  210. it('array sort', function () {
  211. var arr = [{a:1}, {a:2}]
  212. var ob = Observer.create(arr)
  213. ob.on('mutate', spy)
  214. arr.sort(function (a, b) {
  215. return a.a < b.a ? 1 : -1
  216. })
  217. expect(spy.calls.mostRecent().args[0]).toBe('')
  218. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  219. var mutation = spy.calls.mostRecent().args[2]
  220. expect(mutation).toBeDefined()
  221. expect(mutation.method).toBe('sort')
  222. expect(mutation.index).toBeUndefined()
  223. expect(mutation.removed.length).toBe(0)
  224. expect(mutation.inserted.length).toBe(0)
  225. // test index update after mutation
  226. ob.on('set', spy)
  227. arr[1].a = 4
  228. expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
  229. })
  230. it('array reverse', function () {
  231. var arr = [{a:1}, {a:2}]
  232. var ob = Observer.create(arr)
  233. ob.on('mutate', spy)
  234. arr.reverse()
  235. expect(spy.calls.mostRecent().args[0]).toBe('')
  236. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  237. var mutation = spy.calls.mostRecent().args[2]
  238. expect(mutation).toBeDefined()
  239. expect(mutation.method).toBe('reverse')
  240. expect(mutation.index).toBeUndefined()
  241. expect(mutation.removed.length).toBe(0)
  242. expect(mutation.inserted.length).toBe(0)
  243. // test index update after mutation
  244. ob.on('set', spy)
  245. arr[1].a = 4
  246. expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
  247. })
  248. it('object.$add', function () {
  249. var obj = {a:{b:1}}
  250. var ob = Observer.create(obj)
  251. ob.on('add', spy)
  252. // ignore existing keys
  253. obj.$add('a', 123)
  254. expect(spy.calls.count()).toBe(0)
  255. // add event
  256. var add = {d:2}
  257. obj.a.$add('c', add)
  258. expect(spy).toHaveBeenCalledWith('a.c', add, undefined)
  259. // check if add object is properly observed
  260. ob.on('set', spy)
  261. obj.a.c.d = 3
  262. expect(spy).toHaveBeenCalledWith('a.c.d', 3, undefined)
  263. })
  264. it('object.$delete', function () {
  265. var obj = {a:{b:1}}
  266. var ob = Observer.create(obj)
  267. ob.on('delete', spy)
  268. // ignore non-present key
  269. obj.$delete('c')
  270. expect(spy.calls.count()).toBe(0)
  271. obj.a.$delete('b')
  272. expect(spy).toHaveBeenCalledWith('a.b', undefined, undefined)
  273. })
  274. it('array.$set', function () {
  275. var arr = [{a:1}, {a:2}]
  276. var ob = Observer.create(arr)
  277. ob.on('mutate', spy)
  278. var inserted = {a:3}
  279. var removed = arr[1]
  280. arr.$set(1, inserted)
  281. expect(spy.calls.mostRecent().args[0]).toBe('')
  282. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  283. var mutation = spy.calls.mostRecent().args[2]
  284. expect(mutation).toBeDefined()
  285. expect(mutation.method).toBe('splice')
  286. expect(mutation.index).toBe(1)
  287. expect(mutation.removed.length).toBe(1)
  288. expect(mutation.inserted.length).toBe(1)
  289. expect(mutation.removed[0]).toBe(removed)
  290. expect(mutation.inserted[0]).toBe(inserted)
  291. ob.on('set', spy)
  292. arr[1].a = 4
  293. expect(spy).toHaveBeenCalledWith('1.a', 4, undefined)
  294. })
  295. it('array.$set with out of bound length', function () {
  296. var arr = [{a:1}, {a:2}]
  297. var ob = Observer.create(arr)
  298. var inserted = {a:3}
  299. arr.$set(3, inserted)
  300. expect(arr.length).toBe(4)
  301. expect(arr[2]).toBeUndefined()
  302. expect(arr[3]).toBe(inserted)
  303. })
  304. it('array.$remove', function () {
  305. var arr = [{a:1}, {a:2}]
  306. var ob = Observer.create(arr)
  307. ob.on('mutate', spy)
  308. var removed = arr.$remove(0)
  309. expect(spy.calls.mostRecent().args[0]).toBe('')
  310. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  311. var mutation = spy.calls.mostRecent().args[2]
  312. expect(mutation).toBeDefined()
  313. expect(mutation.method).toBe('splice')
  314. expect(mutation.index).toBe(0)
  315. expect(mutation.removed.length).toBe(1)
  316. expect(mutation.inserted.length).toBe(0)
  317. expect(mutation.removed[0]).toBe(removed)
  318. ob.on('set', spy)
  319. arr[0].a = 3
  320. expect(spy).toHaveBeenCalledWith('0.a', 3, undefined)
  321. })
  322. it('array.$remove object', function () {
  323. var arr = [{a:1}, {a:2}]
  324. var ob = Observer.create(arr)
  325. ob.on('mutate', spy)
  326. var removed = arr.$remove(arr[0])
  327. expect(spy.calls.mostRecent().args[0]).toBe('')
  328. expect(spy.calls.mostRecent().args[1]).toBe(arr)
  329. var mutation = spy.calls.mostRecent().args[2]
  330. expect(mutation).toBeDefined()
  331. expect(mutation.method).toBe('splice')
  332. expect(mutation.index).toBe(0)
  333. expect(mutation.removed.length).toBe(1)
  334. expect(mutation.inserted.length).toBe(0)
  335. expect(mutation.removed[0]).toBe(removed)
  336. ob.on('set', spy)
  337. arr[0].a = 3
  338. expect(spy).toHaveBeenCalledWith('0.a', 3, undefined)
  339. })
  340. it('shared observe', function () {
  341. var obj = { a: 1 }
  342. var parentA = { child1: obj }
  343. var parentB = { child2: obj }
  344. var obA = Observer.create(parentA)
  345. var obB = Observer.create(parentB)
  346. obA.on('set', spy)
  347. obB.on('set', spy)
  348. obj.a = 2
  349. expect(spy.calls.count()).toBe(2)
  350. expect(spy).toHaveBeenCalledWith('child1.a', 2, undefined)
  351. expect(spy).toHaveBeenCalledWith('child2.a', 2, undefined)
  352. // test unobserve
  353. parentA.child1 = null
  354. obj.a = 3
  355. expect(spy.calls.count()).toBe(4)
  356. expect(spy).toHaveBeenCalledWith('child1', null, undefined)
  357. expect(spy).toHaveBeenCalledWith('child2.a', 3, undefined)
  358. })
  359. })