Skip to content

Commit 128b534

Browse files
committed
fix: reconcile the overridden prototype of component and _Vue mocks and mixins
1 parent e8d9547 commit 128b534

File tree

2 files changed

+51
-23
lines changed

2 files changed

+51
-23
lines changed

Diff for: packages/create-instance/create-instance.js

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @flow
22

3+
import Vue from 'vue'
34
import { createSlotVNodes } from './create-slot-vnodes'
45
import addMocks from './add-mocks'
56
import { addEventLogger } from './log-events'
@@ -109,10 +110,35 @@ export default function createInstance (
109110
component.options._base = _Vue
110111
}
111112

113+
function getRootVueProto (obj) {
114+
while (obj) {
115+
if (Object.getPrototypeOf(obj) === Vue.prototype) {
116+
return obj
117+
}
118+
119+
obj = Object.getPrototypeOf(obj)
120+
}
121+
}
122+
123+
function getExtendedComponent (component, instanceOptions) {
124+
// extend _Vue to merge the mixins on _Vue
125+
const extendedComponent = component.extend(_Vue).extend(instanceOptions)
126+
127+
// cache subclass constructor
128+
component.options._Ctor[extendedComponent.cid] = extendedComponent
129+
130+
// to keep the possible overridden prototype and _Vue mocks on prototype,
131+
// we need change the proto chains manually
132+
// @see https://github.com/vuejs/vue-test-utils/pull/856
133+
const root = getRootVueProto(extendedComponent.prototype)
134+
Object.setPrototypeOf(root, _Vue.prototype)
135+
136+
return extendedComponent
137+
}
138+
112139
// extend component from _Vue to add properties and mixins
113-
// extend does not work correctly for sub class components in Vue < 2.2
114-
const Constructor = typeof component === 'function' && vueVersion < 2.3
115-
? component.extend(instanceOptions)
140+
const Constructor = typeof component === 'function'
141+
? getExtendedComponent(component, instanceOptions)
116142
: _Vue.extend(component).extend(instanceOptions)
117143

118144
// Keep reference to component mount was called with

Diff for: test/specs/mount.spec.js

+22-20
Original file line numberDiff line numberDiff line change
@@ -156,27 +156,29 @@ describeRunIf(process.env.TEST_ENV !== 'node', 'mount', () => {
156156
expect(stub).not.called
157157
})
158158

159-
it.skip('overrides component prototype', () => {
160-
const mountSpy = sinon.spy()
161-
const destroySpy = sinon.spy()
162-
const Component = Vue.extend({})
163-
const { $mount: originalMount, $destroy: originalDestroy } = Component.prototype
164-
Component.prototype.$mount = function (...args) {
165-
originalMount.apply(this, args)
166-
mountSpy()
167-
return this
168-
}
169-
Component.prototype.$destroy = function () {
170-
originalDestroy.apply(this)
171-
destroySpy()
172-
}
159+
itDoNotRunIf(
160+
vueVersion < 2.3,
161+
'overrides component prototype', () => {
162+
const mountSpy = sinon.spy()
163+
const destroySpy = sinon.spy()
164+
const Component = Vue.extend({})
165+
const { $mount: originalMount, $destroy: originalDestroy } = Component.prototype
166+
Component.prototype.$mount = function (...args) {
167+
originalMount.apply(this, args)
168+
mountSpy()
169+
return this
170+
}
171+
Component.prototype.$destroy = function () {
172+
originalDestroy.apply(this)
173+
destroySpy()
174+
}
173175

174-
const wrapper = mount(Component)
175-
expect(mountSpy).called
176-
expect(destroySpy).not.called
177-
wrapper.destroy()
178-
expect(destroySpy).called
179-
})
176+
const wrapper = mount(Component)
177+
expect(mountSpy).called
178+
expect(destroySpy).not.called
179+
wrapper.destroy()
180+
expect(destroySpy).called
181+
})
180182

181183
// Problems accessing options of twice extended components in Vue < 2.3
182184
itDoNotRunIf(vueVersion < 2.3, 'compiles extended components', () => {

0 commit comments

Comments
 (0)