options_spec.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. var _ = require('../../../../src/util')
  2. var Vue = require('../../../../src/vue')
  3. var merge = _.mergeOptions
  4. var resolveAsset = _.resolveAsset
  5. describe('Util - Option merging', function () {
  6. beforeEach(function () {
  7. spyOn(_, 'warn')
  8. })
  9. it('default strat', function () {
  10. // child undefined
  11. var res = merge({replace: true}, {}).replace
  12. expect(res).toBe(true)
  13. // child overwrite
  14. res = merge({replace: true}, {replace: false}).replace
  15. expect(res).toBe(false)
  16. })
  17. it('hooks & props', function () {
  18. var fn1 = function () {}
  19. var fn2 = function () {}
  20. var res
  21. // parent undefined
  22. res = merge({}, {created: fn1}).created
  23. expect(Array.isArray(res)).toBe(true)
  24. expect(res.length).toBe(1)
  25. expect(res[0]).toBe(fn1)
  26. // child undefined
  27. res = merge({created: [fn1]}, {}).created
  28. expect(Array.isArray(res)).toBe(true)
  29. expect(res.length).toBe(1)
  30. expect(res[0]).toBe(fn1)
  31. // both defined
  32. res = merge({created: [fn1]}, {created: fn2}).created
  33. expect(Array.isArray(res)).toBe(true)
  34. expect(res.length).toBe(2)
  35. expect(res[0]).toBe(fn1)
  36. expect(res[1]).toBe(fn2)
  37. // both arrays
  38. res = merge({props: [1]}, {props: [2]}).props
  39. expect(Array.isArray(res)).toBe(true)
  40. expect(res.length).toBe(2)
  41. expect(res[0]).toBe(1)
  42. expect(res[1]).toBe(2)
  43. })
  44. it('events', function () {
  45. // no parent
  46. res = merge({}, {events: 1})
  47. expect(res.events).toBe(1)
  48. // no child
  49. res = merge({events: 1}, {})
  50. expect(res.events).toBe(1)
  51. var fn1 = function () {}
  52. var fn2 = function () {}
  53. var fn3 = function () {}
  54. var parent = {
  55. events: {
  56. 'fn1': [fn1, fn2],
  57. 'fn2': fn2
  58. }
  59. }
  60. var child = {
  61. events: {
  62. 'fn1': fn3,
  63. 'fn2': fn3,
  64. 'fn3': fn3
  65. }
  66. }
  67. var res = merge(parent, child).events
  68. assertRes(res.fn1, [fn1, fn2, fn3])
  69. assertRes(res.fn2, [fn2, fn3])
  70. assertRes(res.fn3, [fn3])
  71. function assertRes (res, expected) {
  72. expect(Array.isArray(res)).toBe(true)
  73. expect(res.length).toBe(expected.length)
  74. var i = expected.length
  75. while (i--) {
  76. expect(res[i]).toBe(expected[i])
  77. }
  78. }
  79. })
  80. it('normal object hashes', function () {
  81. var fn1 = function () {}
  82. var fn2 = function () {}
  83. var res
  84. // parent undefined
  85. res = merge({}, {methods: {test: fn1}}).methods
  86. expect(res.test).toBe(fn1)
  87. // child undefined
  88. res = merge({methods: {test: fn1}}, {}).methods
  89. expect(res.test).toBe(fn1)
  90. // both defined
  91. var parent = {methods: {test: fn1}}
  92. res = merge(parent, {methods: {test2: fn2}}).methods
  93. expect(res.test).toBe(fn1)
  94. expect(res.test2).toBe(fn2)
  95. })
  96. it('assets', function () {
  97. var asset1 = {}
  98. var asset2 = {}
  99. var res = merge(
  100. { directives: { a: asset1 }},
  101. { directives: { b: asset2 }}
  102. ).directives
  103. expect(res.a).toBe(asset1)
  104. expect(res.b).toBe(asset2)
  105. })
  106. it('guard components', function () {
  107. var res = merge({
  108. components: null
  109. }, {
  110. components: {
  111. test: { template: 'hi' }
  112. }
  113. })
  114. expect(typeof res.components.test).toBe('function')
  115. expect(res.components.test.options.id).toBe('test')
  116. expect(res.components.test.super).toBe(Vue)
  117. })
  118. it('guard components warn built-in elements', function () {
  119. merge({
  120. components: null
  121. }, {
  122. components: {
  123. a: { template: 'hi' }
  124. }
  125. })
  126. expect(hasWarned(_, 'Do not use built-in HTML elements')).toBe(true)
  127. })
  128. it('should ignore non-function el & data in class merge', function () {
  129. var res = merge({}, {el: 1, data: 2})
  130. expect(res.el).toBeUndefined()
  131. expect(res.data).toBeUndefined()
  132. })
  133. it('class el merge', function () {
  134. function fn1 () {}
  135. function fn2 () {}
  136. var res = merge({el: fn1}, {el: fn2})
  137. expect(res.el).toBe(fn2)
  138. })
  139. it('class data merge', function () {
  140. function fn1 () {
  141. return { a: 1, c: 4, d: { e: 1 }}
  142. }
  143. function fn2 () {
  144. return { a: 2, b: 3, d: { f: 2 }}
  145. }
  146. // both present
  147. var res = merge({data: fn1}, {data: fn2}).data()
  148. expect(res.a).toBe(2)
  149. expect(res.b).toBe(3)
  150. expect(res.c).toBe(4)
  151. expect(res.d.e).toBe(1)
  152. expect(res.d.f).toBe(2)
  153. // only parent
  154. res = merge({data: fn1}, {}).data()
  155. expect(res.a).toBe(1)
  156. expect(res.b).toBeUndefined()
  157. expect(res.c).toBe(4)
  158. expect(res.d.e).toBe(1)
  159. expect(res.d.f).toBeUndefined()
  160. })
  161. it('instanace el merge', function () {
  162. var vm = {} // mock vm presence
  163. function fn1 () {
  164. expect(this).toBe(vm)
  165. return 1
  166. }
  167. function fn2 () {
  168. expect(this).toBe(vm)
  169. return 2
  170. }
  171. // both functions
  172. var res = merge({el: fn1}, {el: fn2}, vm)
  173. expect(res.el).toBe(2)
  174. // direct instance el
  175. res = merge({el: fn1}, {el: 2}, vm)
  176. expect(res.el).toBe(2)
  177. // no parent
  178. res = merge({}, {el: 2}, vm)
  179. expect(res.el).toBe(2)
  180. // no child
  181. res = merge({el: fn1}, {}, vm)
  182. expect(res.el).toBe(1)
  183. })
  184. it('instance data merge with no instance data', function () {
  185. var res = merge(
  186. {data: function () {
  187. return { a: 1}
  188. }},
  189. {}, // no instance data
  190. {} // mock vm presence
  191. )
  192. expect(res.data().a).toBe(1)
  193. })
  194. it('instance data merge with default data function', function () {
  195. var vm = {} // mock vm presence
  196. var res = merge(
  197. // component default
  198. { data: function () {
  199. expect(this).toBe(vm)
  200. return {
  201. a: 1,
  202. b: 2
  203. }
  204. }},
  205. { data: { a: 2 }}, // instance data
  206. vm
  207. )
  208. var data = res.data()
  209. expect(data.a).toBe(2)
  210. expect(data.b).toBe(2)
  211. })
  212. it('already observed instance data merge with default data', function () {
  213. var Observer = require('../../../../src/observer')
  214. var instanceData = { a: 123 }
  215. // observe it
  216. Observer.create(instanceData)
  217. var res = merge(
  218. {
  219. data: function () { return { b: 234} }
  220. },
  221. {
  222. data: instanceData
  223. },
  224. {}
  225. )
  226. var data = res.data()
  227. expect(data.a).toBe(123)
  228. expect(data.b).toBe(234)
  229. expect(Object.getOwnPropertyDescriptor(data, 'b').get).toBeTruthy()
  230. })
  231. it('mixins', function () {
  232. var a = {}
  233. var b = {}
  234. var c = {}
  235. var d = {}
  236. var f1 = function () {}
  237. var f2 = function () {}
  238. var f3 = function () {}
  239. var f4 = function () {}
  240. var mixinA = { a: 1, directives: { a: a }, created: f2 }
  241. var mixinB = { b: 1, directives: { b: b }, created: f3 }
  242. var res = merge(
  243. { a: 2, directives: { c: c }, created: [f1] },
  244. { directives: { d: d }, mixins: [mixinA, mixinB], created: f4 }
  245. )
  246. expect(res.a).toBe(1)
  247. expect(res.b).toBe(1)
  248. expect(res.directives.a).toBe(a)
  249. expect(res.directives.b).toBe(b)
  250. expect(res.directives.c).toBe(c)
  251. expect(res.directives.d).toBe(d)
  252. expect(res.created[0]).toBe(f1)
  253. expect(res.created[1]).toBe(f2)
  254. expect(res.created[2]).toBe(f3)
  255. expect(res.created[3]).toBe(f4)
  256. })
  257. it('Array assets', function () {
  258. var a = {
  259. components: {
  260. a: Vue.extend({})
  261. }
  262. }
  263. var b = {
  264. components: [{ id: 'b' }]
  265. }
  266. var res = merge(a, b)
  267. expect(res.components.a).toBe(a.components.a)
  268. // b.components is guarded and converted to object hash
  269. expect(res.components.b).toBe(b.components.b)
  270. })
  271. it('warn Array assets without id', function () {
  272. var a = {
  273. components: {
  274. a: Vue.extend({})
  275. }
  276. }
  277. var b = {
  278. components: [{}]
  279. }
  280. merge(a, b)
  281. expect(hasWarned(_, 'must provide an id')).toBe(true)
  282. })
  283. })
  284. describe('Util - Option resolveAsset', function () {
  285. var vm
  286. beforeEach(function () {
  287. vm = new Vue({
  288. data: {},
  289. components: {
  290. 'hyphenated-component': {
  291. template: 'hi'
  292. },
  293. camelCasedComponent: {
  294. template: 'yo'
  295. },
  296. PascalCasedComponent: {
  297. template: 'ho'
  298. }
  299. }
  300. })
  301. })
  302. it('resolves', function () {
  303. expect(resolveAsset(vm.$options, 'components', 'hyphenated-component')).toBeTruthy()
  304. expect(resolveAsset(vm.$options, 'components', 'camel-cased-component')).toBeTruthy()
  305. expect(resolveAsset(vm.$options, 'components', 'pascal-cased-component')).toBeTruthy()
  306. })
  307. })