diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js
index db4180acd..41e89f92d 100644
--- a/packages/test-utils/src/wrapper.js
+++ b/packages/test-utils/src/wrapper.js
@@ -658,13 +658,32 @@ export default class Wrapper implements BaseWrapper {
)
}
+ // SetProps on object prop child changes trigger computed or watcher
+ // https://github.com/vuejs/vue-test-utils/issues/761
+ let newData
+ if (
+ typeof data[key] === 'object' &&
+ data[key] !== null &&
+ !Array.isArray(data[key])
+ ) {
+ newData = mergeWith(
+ Object.create(Object.getPrototypeOf(data[key])),
+ data[key],
+ (objValue, srcValue) => {
+ return Array.isArray(srcValue) ? srcValue : undefined
+ }
+ )
+ } else {
+ newData = data[key]
+ }
+
if (this.vm && this.vm._props) {
- this.vm._props[key] = data[key]
+ this.vm._props[key] = newData
} else {
// $FlowIgnore : Problem with possibly null this.vm
- this.vm[key] = data[key]
+ this.vm[key] = newData
// $FlowIgnore : Problem with possibly null this.vm.$options
- this.vm.$options.propsData[key] = data[key]
+ this.vm.$options.propsData[key] = newData
}
})
// $FlowIgnore : Problem with possibly null this.vm
diff --git a/test/specs/wrapper/setProps.spec.js b/test/specs/wrapper/setProps.spec.js
index a275f1ab7..407eacb4a 100644
--- a/test/specs/wrapper/setProps.spec.js
+++ b/test/specs/wrapper/setProps.spec.js
@@ -169,6 +169,110 @@ describeWithShallowAndMount('setProps', mountingMethod => {
expect(wrapper.vm.data).to.equal('1,2,3,4,5')
})
+ it('runs computed when prop is object', () => {
+ class TestClass {
+ constructor (text) {
+ this._text = text
+ }
+
+ get text () {
+ return this._text
+ }
+
+ set text (text) {
+ this._text = text
+ }
+ }
+
+ const TestComponent = {
+ template: `
+
{{ shallowObjText }}
+
{{ deepObjText }}
+
{{ classText }}
+
`,
+ props: {
+ shallowObj: Object,
+ deepObj: Object,
+ classInstance: TestClass
+ },
+ computed: {
+ shallowObjText () {
+ return this.shallowObj.text
+ },
+ deepObjText () {
+ return this.deepObj.obj.text
+ },
+ classText () {
+ return this.classInstance.text
+ }
+ }
+ }
+
+ const shallowObj = {
+ text: 'initial shallow'
+ }
+ const deepObj = {
+ obj: {
+ text: 'initial deep'
+ }
+ }
+ const classInstance = new TestClass('initial class')
+ const wrapper = mountingMethod(TestComponent, {
+ propsData: { shallowObj, deepObj, classInstance }
+ })
+ const shallowWraper = wrapper.find('.shallow')
+ const deepWrapper = wrapper.find('.deep')
+ const classWrapper = wrapper.find('.class')
+
+ expect(shallowWraper.text()).to.equal('initial shallow')
+ expect(deepWrapper.text()).to.equal('initial deep')
+ expect(classWrapper.text()).to.equal('initial class')
+
+ shallowObj.text = 'updated shallow'
+ deepObj.obj.text = 'updated deep'
+ classInstance.text = 'updated class'
+ wrapper.setProps({ shallowObj, deepObj, classInstance })
+ expect(shallowWraper.text()).to.equal('updated shallow')
+ expect(deepWrapper.text()).to.equal('updated deep')
+ expect(classWrapper.text()).to.equal('updated class')
+ })
+
+ it('runs watcher when prop is object', () => {
+ const TestComponent = {
+ template: ``,
+ props: {
+ obj: Object
+ },
+ data: () => ({
+ watchText: 'initial'
+ }),
+ watch: {
+ 'obj.text': 'execute'
+ },
+ methods: {
+ execute () {
+ this.watchText = 'updated'
+ }
+ }
+ }
+
+ const obj = {
+ text: 'initial shallow'
+ }
+ const wrapper = mountingMethod(TestComponent, {
+ propsData: { obj }
+ })
+ const watchWrapper = wrapper.find('.watch')
+
+ expect(watchWrapper.text()).to.equal('initial')
+
+ obj.text = 'updated shallow'
+ wrapper.setProps({ obj })
+ expect(watchWrapper.text()).to.equal('updated')
+ })
+
it('throws an error if node is not a Vue instance', () => {
const message = 'wrapper.setProps() can only be called on a Vue instance'
const compiled = compileToFunctions('')