observer.js 18 KB

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