observer_spec.js 11 KB

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