mixin.spec.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import Vue from 'vue'
  2. describe('Global API: mixin', () => {
  3. let options
  4. beforeEach(() => { options = Vue.options })
  5. afterEach(() => { Vue.options = options })
  6. it('should work', () => {
  7. const spy = jasmine.createSpy('global mixin')
  8. Vue.mixin({
  9. created () {
  10. spy(this.$options.myOption)
  11. }
  12. })
  13. new Vue({
  14. myOption: 'hello'
  15. })
  16. expect(spy).toHaveBeenCalledWith('hello')
  17. })
  18. it('should work for constructors created before mixin is applied', () => {
  19. const calls = []
  20. const Test = Vue.extend({
  21. name: 'test',
  22. beforeCreate () {
  23. calls.push(this.$options.myOption + ' local')
  24. }
  25. })
  26. Vue.mixin({
  27. beforeCreate () {
  28. calls.push(this.$options.myOption + ' global')
  29. }
  30. })
  31. expect(Test.options.name).toBe('test')
  32. new Test({
  33. myOption: 'hello'
  34. })
  35. expect(calls).toEqual(['hello global', 'hello local'])
  36. })
  37. // #3957
  38. it('should work for global props', () => {
  39. const Test = Vue.extend({
  40. template: `<div>{{ prop }}</div>`
  41. })
  42. Vue.mixin({
  43. props: ['prop']
  44. })
  45. // test child component
  46. const vm = new Vue({
  47. template: '<test prop="hi"></test>',
  48. components: { Test }
  49. }).$mount()
  50. expect(vm.$el.textContent).toBe('hi')
  51. })
  52. // vue-loader#433
  53. it('should not drop late-set render functions', () => {
  54. const Test = Vue.extend({})
  55. Test.options.render = h => h('div', 'hello')
  56. Vue.mixin({})
  57. const vm = new Vue({
  58. render: h => h(Test)
  59. }).$mount()
  60. expect(vm.$el.textContent).toBe('hello')
  61. })
  62. // #4266
  63. it('should not drop scopedId', () => {
  64. const Test = Vue.extend({})
  65. Test.options._scopeId = 'foo'
  66. Vue.mixin({})
  67. const vm = new Test({
  68. template: '<div><p>hi</p></div>'
  69. }).$mount()
  70. expect(vm.$el.children[0].hasAttribute('foo')).toBe(true)
  71. })
  72. // #4976
  73. it('should not drop late-attached custom options on existing constructors', () => {
  74. const baseSpy = jasmine.createSpy('base')
  75. const Base = Vue.extend({
  76. beforeCreate: baseSpy
  77. })
  78. const Test = Base.extend({})
  79. // Inject options later
  80. // vue-loader and vue-hot-reload-api are doing like this
  81. Test.options.computed = {
  82. $style: () => 123
  83. }
  84. const spy = jasmine.createSpy('late attached')
  85. Test.options.beforeCreate = Test.options.beforeCreate.concat(spy)
  86. // Update super constructor's options
  87. const mixinSpy = jasmine.createSpy('mixin')
  88. Vue.mixin({
  89. beforeCreate: mixinSpy
  90. })
  91. // mount the component
  92. const vm = new Test({
  93. template: '<div>{{ $style }}</div>'
  94. }).$mount()
  95. expect(spy.calls.count()).toBe(1)
  96. expect(baseSpy.calls.count()).toBe(1)
  97. expect(mixinSpy.calls.count()).toBe(1)
  98. expect(vm.$el.textContent).toBe('123')
  99. expect(vm.$style).toBe(123)
  100. // Should not be dropped
  101. expect(Test.options.computed.$style()).toBe(123)
  102. expect(Test.options.beforeCreate).toEqual([mixinSpy, baseSpy, spy])
  103. })
  104. // vue-class-component#83
  105. it('should work for a constructor mixin', () => {
  106. const spy = jasmine.createSpy('global mixin')
  107. const Mixin = Vue.extend({
  108. created () {
  109. spy(this.$options.myOption)
  110. }
  111. })
  112. Vue.mixin(Mixin)
  113. new Vue({
  114. myOption: 'hello'
  115. })
  116. expect(spy).toHaveBeenCalledWith('hello')
  117. })
  118. // vue-class-component#87
  119. it('should not drop original lifecycle hooks', () => {
  120. const base = jasmine.createSpy('base')
  121. const Base = Vue.extend({
  122. beforeCreate: base
  123. })
  124. const injected = jasmine.createSpy('injected')
  125. // inject a function
  126. Base.options.beforeCreate = Base.options.beforeCreate.concat(injected)
  127. Vue.mixin({})
  128. new Base({})
  129. expect(base).toHaveBeenCalled()
  130. expect(injected).toHaveBeenCalled()
  131. })
  132. // #8595
  133. it('chain call', () => {
  134. expect(Vue.mixin({})).toBe(Vue)
  135. })
  136. // #9198
  137. it('should not mix global mixin lifecycle hook twice', () => {
  138. const spy = jasmine.createSpy('global mixed in lifecycle hook')
  139. Vue.mixin({
  140. created: spy
  141. })
  142. const mixin1 = Vue.extend({
  143. methods: {
  144. a() {}
  145. }
  146. })
  147. const mixin2 = Vue.extend({
  148. mixins: [mixin1]
  149. })
  150. const Child = Vue.extend({
  151. mixins: [mixin2],
  152. })
  153. const vm = new Child()
  154. expect(typeof vm.$options.methods.a).toBe('function')
  155. expect(spy.calls.count()).toBe(1)
  156. })
  157. })