options_spec.js 9.0 KB

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