instance_scope_spec.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /**
  2. * Test property proxy, scope inheritance,
  3. * data event propagation and data sync
  4. */
  5. var Vue = require('../../../src/vue')
  6. var Observer = require('../../../src/observe/observer')
  7. var u = undefined
  8. Observer.pathDelimiter = '.'
  9. describe('Scope', function () {
  10. describe('basic', function () {
  11. var vm = new Vue({
  12. data: {
  13. a: 1,
  14. b: {
  15. c: 2
  16. }
  17. }
  18. })
  19. it('should copy over data properties', function () {
  20. expect(vm.$scope.a).toBe(vm.$data.a)
  21. expect(vm.$scope.b).toBe(vm.$data.b)
  22. })
  23. it('should proxy these properties', function () {
  24. expect(vm.a).toBe(vm.$scope.a)
  25. expect(vm.b).toBe(vm.$scope.b)
  26. })
  27. it('should trigger set events', function () {
  28. var spy = jasmine.createSpy('basic')
  29. vm.$observer.on('set', spy)
  30. // set on scope
  31. vm.$scope.a = 2
  32. expect(spy.calls.count()).toBe(1)
  33. expect(spy).toHaveBeenCalledWith('a', 2, u)
  34. // set on vm
  35. vm.b.c = 3
  36. expect(spy.calls.count()).toBe(2)
  37. expect(spy).toHaveBeenCalledWith('b.c', 3, u)
  38. })
  39. it('should trigger add/delete events', function () {
  40. var spy = jasmine.createSpy('instantiation')
  41. vm.$observer
  42. .on('add', spy)
  43. .on('delete', spy)
  44. // add on scope
  45. vm.$scope.$add('c', 123)
  46. expect(spy.calls.count()).toBe(1)
  47. expect(spy).toHaveBeenCalledWith('c', 123, u)
  48. // delete on scope
  49. vm.$scope.$delete('c')
  50. expect(spy.calls.count()).toBe(2)
  51. expect(spy).toHaveBeenCalledWith('c', u, u)
  52. // vm $add/$delete are tested in the api suite
  53. })
  54. })
  55. describe('data sync', function () {
  56. var data = {
  57. a: 1,
  58. b: {
  59. c: 2
  60. }
  61. }
  62. var vm = new Vue({
  63. data: data
  64. })
  65. it('should retain data reference', function () {
  66. expect(vm.$data).toBe(data)
  67. })
  68. it('should sync set', function () {
  69. // vm -> data
  70. vm.a = 2
  71. expect(data.a).toBe(2)
  72. // data -> vm
  73. data.b = {d:3}
  74. expect(vm.$scope.b).toBe(data.b)
  75. expect(vm.b).toBe(data.b)
  76. })
  77. it('should sync add', function () {
  78. // vm -> data
  79. vm.$scope.$add('c', 123)
  80. expect(data.c).toBe(123)
  81. // data -> vm
  82. data.$add('d', 456)
  83. expect(vm.$scope.d).toBe(456)
  84. expect(vm.d).toBe(456)
  85. })
  86. it('should sync delete', function () {
  87. // vm -> data
  88. vm.$scope.$delete('d')
  89. expect(data.hasOwnProperty('d')).toBe(false)
  90. // data -> vm
  91. data.$delete('c')
  92. expect(vm.$scope.hasOwnProperty('c')).toBe(false)
  93. expect(vm.hasOwnProperty('c')).toBe(false)
  94. })
  95. })
  96. describe('inheritance', function () {
  97. var parent = new Vue({
  98. data: {
  99. a: 'parent a',
  100. b: { c: 2 },
  101. c: 'parent c',
  102. arr: [{a:1},{a:2}]
  103. }
  104. })
  105. var child = new Vue({
  106. parent: parent,
  107. data: {
  108. a: 'child a'
  109. }
  110. })
  111. it('child should inherit parent data on scope', function () {
  112. expect(child.$scope.b).toBe(parent.b) // object
  113. expect(child.$scope.c).toBe(parent.c) // primitive value
  114. })
  115. it('child should not ineherit data on instance', function () {
  116. expect(child.b).toBeUndefined()
  117. expect(child.c).toBeUndefined()
  118. })
  119. it('child should shadow parent property with same key', function () {
  120. expect(parent.a).toBe('parent a')
  121. expect(child.$scope.a).toBe('child a')
  122. expect(child.a).toBe('child a')
  123. })
  124. it('setting scope properties on child should affect parent', function () {
  125. child.$scope.c = 'modified by child'
  126. expect(parent.c).toBe('modified by child')
  127. })
  128. it('events on parent should propagate down to child', function () {
  129. // when a shadowed property changed on parent scope,
  130. // the event should NOT be propagated down
  131. var spy = jasmine.createSpy('inheritance')
  132. child.$observer.on('set', spy)
  133. parent.c = 'c changed'
  134. expect(spy.calls.count()).toBe(1)
  135. expect(spy).toHaveBeenCalledWith('c', 'c changed', u)
  136. spy = jasmine.createSpy('inheritance')
  137. child.$observer.on('add', spy)
  138. parent.$scope.$add('e', 123)
  139. expect(spy.calls.count()).toBe(1)
  140. expect(spy).toHaveBeenCalledWith('e', 123, u)
  141. spy = jasmine.createSpy('inheritance')
  142. child.$observer.on('delete', spy)
  143. parent.$scope.$delete('e')
  144. expect(spy.calls.count()).toBe(1)
  145. expect(spy).toHaveBeenCalledWith('e', u, u)
  146. spy = jasmine.createSpy('inheritance')
  147. child.$observer.on('mutate', spy)
  148. parent.arr.reverse()
  149. expect(spy.calls.mostRecent().args[0]).toBe('arr')
  150. expect(spy.calls.mostRecent().args[1]).toBe(parent.arr)
  151. expect(spy.calls.mostRecent().args[2].method).toBe('reverse')
  152. })
  153. it('shadowed properties change on parent should not propagate down', function () {
  154. // when a shadowed property changed on parent scope,
  155. // the event should NOT be propagated down
  156. var spy = jasmine.createSpy('inheritance')
  157. child.$observer.on('set', spy)
  158. parent.a = 'a changed'
  159. expect(spy.calls.count()).toBe(0)
  160. })
  161. })
  162. describe('inheritance with data sync on parent data', function () {
  163. var parent = new Vue({
  164. data: {
  165. arr: [{a:1},{a:2}]
  166. }
  167. })
  168. var child = new Vue({
  169. parent: parent,
  170. data: parent.arr[0]
  171. })
  172. it('should trigger proper events', function () {
  173. var parentSpy = jasmine.createSpy('parent')
  174. var childSpy = jasmine.createSpy('child')
  175. parent.$observer.on('set', parentSpy)
  176. child.$observer.on('set', childSpy)
  177. child.a = 3
  178. // make sure data sync is working
  179. expect(parent.arr[0].a).toBe(3)
  180. expect(parentSpy.calls.count()).toBe(1)
  181. expect(parentSpy).toHaveBeenCalledWith('arr.0.a', 3, u)
  182. expect(childSpy.calls.count()).toBe(2)
  183. expect(childSpy).toHaveBeenCalledWith('a', 3, u)
  184. expect(childSpy).toHaveBeenCalledWith('arr.0.a', 3, u)
  185. })
  186. })
  187. describe('swapping $data', function () {
  188. var oldData = { a: 1, c: 4 }
  189. var newData = { a: 2, b: 3 }
  190. var vm = new Vue({
  191. data: oldData
  192. })
  193. var vmSpy = jasmine.createSpy('vm')
  194. var vmAddSpy = jasmine.createSpy('vmAdd')
  195. var oldDataSpy = jasmine.createSpy('oldData')
  196. vm.$observer.on('set', vmSpy)
  197. vm.$observer.on('add', vmAddSpy)
  198. oldData.$observer.on('set', oldDataSpy)
  199. vm.$data = newData
  200. it('should sync new data', function () {
  201. expect(vm._data).toBe(newData)
  202. expect(vm.a).toBe(2)
  203. expect(vm.b).toBe(3)
  204. expect(vmSpy).toHaveBeenCalledWith('a', 2, u)
  205. expect(vmAddSpy).toHaveBeenCalledWith('b', 3, u)
  206. })
  207. it('should unsync old data', function () {
  208. expect(vm.hasOwnProperty('c')).toBe(false)
  209. vm.a = 3
  210. expect(oldDataSpy.calls.count()).toBe(0)
  211. expect(oldData.a).toBe(1)
  212. expect(newData.a).toBe(3)
  213. })
  214. })
  215. describe('scope teardown', function () {
  216. var parent = new Vue({
  217. data: {
  218. a: 123
  219. }
  220. })
  221. var child = new Vue({
  222. parent: parent
  223. })
  224. var spy = jasmine.createSpy('teardown')
  225. child.$observer.on('set', spy)
  226. it('should stop relaying parent events', function () {
  227. child._teardownScope()
  228. parent.a = 234
  229. expect(spy.calls.count()).toBe(0)
  230. expect(child.$scope).toBeNull()
  231. })
  232. })
  233. describe('computed', function () {
  234. var vm = new Vue({
  235. data: {
  236. a: 'a',
  237. b: 'b'
  238. },
  239. computed: {
  240. c: function () {
  241. expect(this).toBe(vm)
  242. return this.a + this.b
  243. },
  244. d: {
  245. get: function () {
  246. expect(this).toBe(vm)
  247. return this.a + this.b
  248. },
  249. set: function (newVal) {
  250. expect(this).toBe(vm)
  251. var vals = newVal.split(' ')
  252. this.a = vals[0]
  253. this.b = vals[1]
  254. }
  255. }
  256. }
  257. })
  258. it('get', function () {
  259. expect(vm.c).toBe('ab')
  260. expect(vm.d).toBe('ab')
  261. })
  262. it('set', function () {
  263. vm.c = 123 // should do nothing
  264. vm.d = 'c d'
  265. expect(vm.a).toBe('c')
  266. expect(vm.b).toBe('d')
  267. expect(vm.c).toBe('cd')
  268. expect(vm.d).toBe('cd')
  269. })
  270. it('inherit', function () {
  271. var child = new Vue({ parent: vm })
  272. expect(child.$scope.c).toBe('cd')
  273. child.$scope.d = 'e f'
  274. expect(vm.a).toBe('e')
  275. expect(vm.b).toBe('f')
  276. expect(vm.c).toBe('ef')
  277. expect(vm.d).toBe('ef')
  278. expect(child.$scope.a).toBe('e')
  279. expect(child.$scope.b).toBe('f')
  280. expect(child.$scope.c).toBe('ef')
  281. expect(child.$scope.d).toBe('ef')
  282. })
  283. })
  284. describe('methods', function () {
  285. it('should work and have correct context', function () {
  286. var vm = new Vue({
  287. data: {
  288. a: 1
  289. },
  290. methods: {
  291. test: function () {
  292. expect(this instanceof Vue).toBe(true)
  293. return this.a
  294. }
  295. }
  296. })
  297. expect(vm.test()).toBe(1)
  298. expect(vm.$scope.test()).toBe(1)
  299. })
  300. })
  301. })