observer.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. describe('UNIT: Observer', function () {
  2. var Observer = require('vue/src/observer'),
  3. Emitter = require('emitter'),
  4. DepsOb = require('vue/src/deps-parser').observer
  5. describe('Observing Object', function () {
  6. it('should not watch a ViewModel instance', function () {
  7. var obj = new Vue(), ob = new Emitter()
  8. Observer.observe(obj, 'test', ob)
  9. assert.notOk(obj.__observer__)
  10. })
  11. it('should attach hidden observer and values to the object', function () {
  12. var obj = {}, ob = new Emitter()
  13. Observer.observe(obj, 'test', ob)
  14. assert.ok(obj.__observer__ instanceof Emitter)
  15. assert.ok(obj.__observer__.values)
  16. })
  17. it('should emit set events with correct path', setTestFactory({
  18. obj: { a: 1, b: { c: 2 } },
  19. expects: [
  20. { key: 'test.a', val: 1 },
  21. { key: 'test.b.c', val: 3 }
  22. ],
  23. path: 'test'
  24. }))
  25. it('should emit multiple events when a nested object is set', setTestFactory({
  26. obj: { a: 1, b: { c: 2 } },
  27. expects: [
  28. { key: 'test.b', val: { c: 3 } },
  29. { key: 'test.b.c', val: 3, skip: true }
  30. ],
  31. path: 'test'
  32. }))
  33. it('should emit get events on tip values', function () {
  34. DepsOb.active = true
  35. getTestFactory({
  36. obj: { a: 1, b: { c: 2 } },
  37. expects: [
  38. 'test.a',
  39. 'test.b.c'
  40. ],
  41. path: 'test'
  42. })()
  43. DepsOb.active = false
  44. })
  45. it('should emit set when first observing', function () {
  46. var obj = { a: 1, b: { c: 2} },
  47. ob = new Emitter(), i = 0
  48. var expects = [
  49. { key: 'test.a', val: obj.a },
  50. { key: 'test.b', val: obj.b },
  51. { key: 'test.b.c', val: obj.b.c }
  52. ]
  53. ob.on('set', function (key, val) {
  54. var exp = expects[i]
  55. assert.strictEqual(key, exp.key)
  56. assert.strictEqual(val, exp.val)
  57. i++
  58. })
  59. Observer.observe(obj, 'test', ob)
  60. assert.strictEqual(i, expects.length)
  61. })
  62. it('should emit set when watching an already observed object', function () {
  63. var obj = { a: 1, b: { c: 2} },
  64. ob1 = new Emitter(),
  65. ob2 = new Emitter(),
  66. i = 0
  67. Observer.observe(obj, 'test', ob1) // watch first time
  68. var expects = [
  69. { key: 'test.a', val: obj.a },
  70. { key: 'test.b', val: obj.b },
  71. { key: 'test.b.c', val: obj.b.c }
  72. ]
  73. ob2.on('set', function (key, val) {
  74. var exp = expects[i]
  75. assert.strictEqual(key, exp.key)
  76. assert.strictEqual(val, exp.val)
  77. i++
  78. })
  79. Observer.observe(obj, 'test', ob2) // watch again
  80. assert.strictEqual(i, expects.length)
  81. })
  82. })
  83. describe('Observing Array', function () {
  84. var arr = [],
  85. ob = new Emitter()
  86. Observer.observe(arr, 'test', ob)
  87. it('should attach the hidden observer', function () {
  88. assert.ok(arr.__observer__ instanceof Emitter)
  89. })
  90. it('should overwrite the native array mutator methods', function () {
  91. ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
  92. assert.notStrictEqual(arr[method], Array.prototype[method])
  93. })
  94. })
  95. it('should emit set for .length when it mutates', function () {
  96. var emitted = false
  97. ob.once('set', function (key, val) {
  98. assert.strictEqual(key, 'test.length')
  99. assert.strictEqual(val, 1)
  100. emitted = true
  101. })
  102. arr.push(1)
  103. assert.ok(emitted)
  104. })
  105. describe('Mutator Methods', function () {
  106. it('push', function () {
  107. var arg1 = 123,
  108. arg2 = 234,
  109. emitted = false
  110. ob.once('mutate', function (key, array, mutation) {
  111. assert.strictEqual(key, 'test')
  112. assert.strictEqual(array, arr)
  113. assert.strictEqual(array.length, 3)
  114. assert.strictEqual(mutation.method, 'push')
  115. assert.strictEqual(mutation.args.length, 2)
  116. assert.strictEqual(mutation.args[0], arg1)
  117. assert.strictEqual(mutation.args[1], arg2)
  118. assert.strictEqual(mutation.result, arr.length)
  119. emitted = true
  120. })
  121. var r = arr.push(arg1, arg2)
  122. assert.ok(emitted)
  123. assert.strictEqual(r, arr.length)
  124. })
  125. it('pop', function () {
  126. var emitted = false,
  127. expected = arr[arr.length - 1]
  128. ob.once('mutate', function (key, array, mutation) {
  129. assert.strictEqual(key, 'test')
  130. assert.strictEqual(array, arr)
  131. assert.strictEqual(array.length, 2)
  132. assert.strictEqual(mutation.method, 'pop')
  133. assert.strictEqual(mutation.args.length, 0)
  134. assert.strictEqual(mutation.result, expected)
  135. emitted = true
  136. })
  137. var r = arr.pop()
  138. assert.ok(emitted)
  139. assert.strictEqual(r, expected)
  140. })
  141. it('shift', function () {
  142. var emitted = false,
  143. expected = arr[0]
  144. ob.once('mutate', function (key, array, mutation) {
  145. assert.strictEqual(key, 'test')
  146. assert.strictEqual(array, arr)
  147. assert.strictEqual(array.length, 1)
  148. assert.strictEqual(mutation.method, 'shift')
  149. assert.strictEqual(mutation.args.length, 0)
  150. assert.strictEqual(mutation.result, expected)
  151. emitted = true
  152. })
  153. var r = arr.shift()
  154. assert.ok(emitted)
  155. assert.strictEqual(r, expected)
  156. })
  157. it('unshift', function () {
  158. var emitted = false,
  159. arg1 = 456,
  160. arg2 = 678
  161. ob.once('mutate', function (key, array, mutation) {
  162. assert.strictEqual(key, 'test')
  163. assert.strictEqual(array, arr)
  164. assert.strictEqual(array.length, 3)
  165. assert.strictEqual(mutation.method, 'unshift')
  166. assert.strictEqual(mutation.args.length, 2)
  167. assert.strictEqual(mutation.args[0], arg1)
  168. assert.strictEqual(mutation.args[1], arg2)
  169. assert.strictEqual(mutation.result, arr.length)
  170. emitted = true
  171. })
  172. var r = arr.unshift(arg1, arg2)
  173. assert.ok(emitted)
  174. assert.strictEqual(r, arr.length)
  175. })
  176. it('splice', function () {
  177. var emitted = false,
  178. arg1 = 789,
  179. arg2 = 910,
  180. expected = arr[1]
  181. ob.once('mutate', function (key, array, mutation) {
  182. assert.strictEqual(key, 'test')
  183. assert.strictEqual(array, arr)
  184. assert.strictEqual(array.length, 4)
  185. assert.strictEqual(mutation.method, 'splice')
  186. assert.strictEqual(mutation.args.length, 4)
  187. assert.strictEqual(mutation.args[0], 1)
  188. assert.strictEqual(mutation.args[1], 1)
  189. assert.strictEqual(mutation.args[2], arg1)
  190. assert.strictEqual(mutation.args[3], arg2)
  191. assert.strictEqual(mutation.result.length, 1)
  192. assert.strictEqual(mutation.result[0], expected)
  193. emitted = true
  194. })
  195. var r = arr.splice(1, 1, arg1, arg2)
  196. assert.ok(emitted)
  197. assert.strictEqual(r.length, 1)
  198. assert.strictEqual(r[0], expected)
  199. })
  200. it('sort', function () {
  201. var emitted = false,
  202. sorter = function (a, b) {
  203. return a > b ? -1 : 1
  204. },
  205. copy = arr.slice().sort(sorter)
  206. ob.once('mutate', function (key, array, mutation) {
  207. assert.strictEqual(key, 'test')
  208. assert.strictEqual(array, arr)
  209. assert.strictEqual(mutation.method, 'sort')
  210. assert.strictEqual(mutation.args.length, 1)
  211. assert.strictEqual(mutation.result, arr)
  212. for (var i = 0; i < copy.length; i++) {
  213. assert.strictEqual(array[i], copy[i])
  214. }
  215. emitted = true
  216. })
  217. var r = arr.sort(sorter)
  218. assert.ok(emitted)
  219. assert.strictEqual(r, arr)
  220. })
  221. it('reverse', function () {
  222. var emitted = false,
  223. copy = arr.slice().reverse()
  224. ob.once('mutate', function (key, array, mutation) {
  225. assert.strictEqual(key, 'test')
  226. assert.strictEqual(array, arr)
  227. assert.strictEqual(mutation.method, 'reverse')
  228. assert.strictEqual(mutation.args.length, 0)
  229. assert.strictEqual(mutation.result, arr)
  230. for (var i = 0; i < copy.length; i++) {
  231. assert.strictEqual(array[i], copy[i])
  232. }
  233. emitted = true
  234. })
  235. var r = arr.reverse()
  236. assert.ok(emitted)
  237. assert.strictEqual(r, arr)
  238. })
  239. })
  240. describe('Augmentations', function () {
  241. it('remove (index)', function () {
  242. var emitted = false,
  243. index = ~~(Math.random() * arr.length),
  244. expected = arr[index] = { a: 1 }
  245. ob.once('mutate', function (key, array, mutation) {
  246. emitted = true
  247. assert.strictEqual(mutation.method, 'splice')
  248. assert.strictEqual(mutation.args.length, 2)
  249. assert.strictEqual(mutation.args[0], index)
  250. })
  251. var r = arr.remove(index)
  252. assert.ok(emitted)
  253. assert.strictEqual(r, expected)
  254. })
  255. it('remove (object)', function () {
  256. var emitted = false,
  257. index = ~~(Math.random() * arr.length),
  258. expected = arr[index] = { a: 1 }
  259. ob.once('mutate', function (key, array, mutation) {
  260. emitted = true
  261. assert.strictEqual(mutation.method, 'splice')
  262. assert.strictEqual(mutation.args.length, 2)
  263. assert.strictEqual(mutation.args[0], index)
  264. })
  265. var r = arr.remove(expected)
  266. assert.ok(emitted)
  267. assert.strictEqual(r, expected)
  268. })
  269. it('remove (function)', function () {
  270. var expected = [1001, 1002]
  271. arr.push.apply(arr, expected)
  272. var filter = function (e) {
  273. return e > 1000
  274. },
  275. copy = arr.filter(function (e) {
  276. return e <= 1000
  277. })
  278. var removed = arr.remove(filter)
  279. assert.deepEqual(arr, copy)
  280. assert.deepEqual(expected, removed)
  281. })
  282. it('replace (index)', function () {
  283. var emitted = false,
  284. index = ~~(Math.random() * arr.length),
  285. expected = arr[index] = { a: 1 },
  286. arg = 34567
  287. ob.once('mutate', function (key, array, mutation) {
  288. emitted = true
  289. assert.strictEqual(mutation.method, 'splice')
  290. assert.strictEqual(mutation.args.length, 3)
  291. assert.strictEqual(mutation.args[0], index)
  292. })
  293. var r = arr.replace(index, arg)
  294. assert.ok(emitted)
  295. assert.strictEqual(r, expected)
  296. assert.strictEqual(arr[index], arg)
  297. })
  298. it('replace (object)', function () {
  299. var emitted = false,
  300. index = ~~(Math.random() * arr.length),
  301. expected = arr[index] = { a: 1 },
  302. arg = 45678
  303. ob.once('mutate', function (key, array, mutation) {
  304. emitted = true
  305. assert.strictEqual(mutation.method, 'splice')
  306. assert.strictEqual(mutation.args.length, 3)
  307. assert.strictEqual(mutation.args[0], index)
  308. })
  309. var r = arr.replace(expected, arg)
  310. assert.ok(emitted)
  311. assert.strictEqual(r, expected)
  312. assert.strictEqual(arr[index], arg)
  313. })
  314. it('replace (function)', function () {
  315. arr[0] = 1
  316. arr[1] = 2
  317. arr[2] = 3
  318. var expected = [2, 3, 3],
  319. expectRet = [1, 2]
  320. var replaced = arr.replace(function (e) {
  321. if (e < 3) return e + 1
  322. })
  323. assert.deepEqual(arr, expected)
  324. assert.deepEqual(replaced, expectRet)
  325. })
  326. })
  327. })
  328. describe('Multiple observers', function () {
  329. var ob1 = new Emitter(),
  330. ob2 = new Emitter(),
  331. obj = {a:1}
  332. Observer.observe(obj, 'test', ob1)
  333. Observer.observe(obj, 'test', ob2)
  334. var ob1Called = false,
  335. ob2Called = false
  336. ob1.on('set', function () {
  337. ob1Called = true
  338. })
  339. ob2.on('set', function () {
  340. ob2Called = true
  341. })
  342. it('should trigger events for multiple observers observing the same object', function () {
  343. obj.a = 2
  344. assert.ok(ob1Called)
  345. assert.ok(ob2Called)
  346. })
  347. })
  348. describe('.unobserve()', function () {
  349. var ob1 = new Emitter(),
  350. ob2 = new Emitter(),
  351. obj = {a:1}
  352. Observer.observe(obj, 'test', ob1)
  353. Observer.observe(obj, 'test', ob2)
  354. Observer.unobserve(obj, 'test', ob1)
  355. var ob1Called = false
  356. ob1.on('set', function () {
  357. ob1Called = true
  358. })
  359. var ob2Called = false
  360. ob2.on('set', function () {
  361. ob2Called = true
  362. })
  363. it('should set observer proxies path to null', function () {
  364. assert.strictEqual(ob1.proxies['test.'], null)
  365. })
  366. it('should turn off corresponding event listeners', function () {
  367. var callbacks = obj.__observer__._callbacks
  368. for (var e in callbacks) {
  369. assert.strictEqual(callbacks[e].length, 1)
  370. }
  371. })
  372. it('should no longer emit events', function () {
  373. obj.a = 2
  374. assert.notOk(ob1Called)
  375. assert.ok(ob2Called)
  376. })
  377. })
  378. describe('.ensurePath()', function () {
  379. it('should ensure a path can be accessed without error', function () {
  380. var obj = {},
  381. path = 'a.b.c'
  382. Observer.ensurePath(obj, path)
  383. assert.strictEqual(obj.a.b.c, undefined)
  384. })
  385. })
  386. // describe('.copyPaths()', function () {
  387. // it('should ensure path for all paths that start with the given key', function () {
  388. // var key = 'a',
  389. // obj = {},
  390. // paths = {
  391. // 'a.b.c': 1,
  392. // 'a.d': 2,
  393. // 'e.f': 3,
  394. // 'g': 4
  395. // }
  396. // Observer.ensurePaths(key, obj, paths)
  397. // assert.strictEqual(obj.b.c, undefined)
  398. // assert.strictEqual(obj.d, undefined)
  399. // assert.notOk('f' in obj)
  400. // assert.strictEqual(Object.keys(obj).length, 2)
  401. // })
  402. // })
  403. function setTestFactory (opts) {
  404. return function () {
  405. var ob = new Emitter(),
  406. i = 0,
  407. obj = opts.obj,
  408. expects = opts.expects
  409. Observer.observe(obj, opts.path, ob)
  410. ob.on('set', function (key, val) {
  411. var expect = expects[i]
  412. assert.strictEqual(key, expect.key)
  413. assert.strictEqual(val, expect.val)
  414. i++
  415. })
  416. expects.forEach(function (expect) {
  417. if (expect.skip) return
  418. var path = expect.key.split('.'),
  419. j = 1,
  420. data = obj
  421. while (j < path.length - 1) {
  422. data = data[path[j]]
  423. j++
  424. }
  425. data[path[j]] = expect.val
  426. })
  427. assert.strictEqual(i, expects.length)
  428. }
  429. }
  430. function getTestFactory (opts) {
  431. return function () {
  432. var ob = new Emitter(),
  433. i = 0,
  434. obj = opts.obj,
  435. expects = opts.expects
  436. Observer.observe(obj, opts.path, ob)
  437. ob.on('get', function (key) {
  438. var expected = expects[i]
  439. assert.strictEqual(key, expected)
  440. i++
  441. })
  442. expects.forEach(function (key) {
  443. var path = key.split('.'),
  444. j = 1,
  445. data = obj
  446. while (j < path.length) {
  447. data = data[path[j]]
  448. j++
  449. }
  450. })
  451. assert.strictEqual(i, expects.length)
  452. }
  453. }
  454. })