diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js
index fb7cfc292..d1bc01657 100644
--- a/packages/create-instance/create-instance.js
+++ b/packages/create-instance/create-instance.js
@@ -11,7 +11,7 @@ import createScopedSlots from './create-scoped-slots'
import { createStubsFromStubsObject } from './create-component-stubs'
import { patchCreateElement } from './patch-create-element'
-function createContext(options, scopedSlots) {
+function createContext(options, scopedSlots, currentProps) {
const on = {
...(options.context && options.context.on),
...options.listeners
@@ -21,7 +21,7 @@ function createContext(options, scopedSlots) {
...options.attrs,
// pass as attrs so that inheritAttrs works correctly
// propsData should take precedence over attrs
- ...options.propsData
+ ...currentProps
},
...(options.context || {}),
on,
@@ -98,10 +98,16 @@ export default function createInstance(
parentComponentOptions._provided = options.provide
parentComponentOptions.$_doNotStubChildren = true
parentComponentOptions._isFunctionalContainer = componentOptions.functional
+ const originalDataFn = parentComponentOptions.data
+ parentComponentOptions.data = function() {
+ const originalData = originalDataFn ? originalDataFn() : {}
+ originalData.vueTestUtils_childProps = { ...options.propsData }
+ return originalData
+ }
parentComponentOptions.render = function(h) {
return h(
Constructor,
- createContext(options, scopedSlots),
+ createContext(options, scopedSlots, this.vueTestUtils_childProps),
createChildren(this, h, options)
)
}
diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js
index b8beeca16..bc2a5e6a9 100644
--- a/packages/test-utils/src/wrapper.js
+++ b/packages/test-utils/src/wrapper.js
@@ -1,10 +1,7 @@
// @flow
-
-import Vue from 'vue'
import pretty from 'pretty'
import getSelector from './get-selector'
import { REF_SELECTOR, FUNCTIONAL_OPTIONS, VUE_VERSION } from 'shared/consts'
-import config from './config'
import WrapperArray from './wrapper-array'
import ErrorWrapper from './error-wrapper'
import { throwError, getCheckedEvent, isPhantomJS } from 'shared/util'
@@ -478,8 +475,6 @@ export default class Wrapper implements BaseWrapper {
* Sets vm props
*/
setProps(data: Object): void {
- const originalConfig = Vue.config.silent
- Vue.config.silent = config.silent
if (this.isFunctionalComponent) {
throwError(
`wrapper.setProps() cannot be called on a functional component`
@@ -503,38 +498,26 @@ export default class Wrapper implements BaseWrapper {
)
}
if (
- !this.vm ||
- !this.vm.$options._propKeys ||
- !this.vm.$options._propKeys.some(prop => prop === key)
+ VUE_VERSION <= 2.3 &&
+ // $FlowIgnore : Problem with possibly null this.vm
+ (!this.vm.$options._propKeys ||
+ !this.vm.$options._propKeys.some(prop => prop === key))
) {
- if (VUE_VERSION > 2.3) {
- // $FlowIgnore : Problem with possibly null this.vm
- this.vm.$attrs[key] = data[key]
- return
- }
throwError(
`wrapper.setProps() called with ${key} property which ` +
`is not defined on the component`
)
}
- if (this.vm && this.vm._props) {
- // Set actual props value
- this.vm._props[key] = data[key]
- // $FlowIgnore : Problem with possibly null this.vm
- this.vm[key] = data[key]
- } else {
- // $FlowIgnore : Problem with possibly null this.vm.$options
- this.vm.$options.propsData[key] = data[key]
- // $FlowIgnore : Problem with possibly null this.vm
- this.vm[key] = data[key]
- // $FlowIgnore : Need to call this twice to fix watcher bug in 2.0.x
- this.vm[key] = data[key]
+ if (this.vm && this.vm.$parent) {
+ this.vm.$parent.vueTestUtils_childProps[key] = data[key]
}
})
// $FlowIgnore : Problem with possibly null this.vm
this.vm.$forceUpdate()
- Vue.config.silent = originalConfig
+ // We need to explicitly trigger parent watcher to support sync scenarios
+ // $FlowIgnore : Problem with possibly null this.vm
+ this.vm.$parent._watcher.run()
}
/**
diff --git a/test/resources/components/component-with-watch-immediate.vue b/test/resources/components/component-with-watch-immediate.vue
new file mode 100644
index 000000000..a660b9865
--- /dev/null
+++ b/test/resources/components/component-with-watch-immediate.vue
@@ -0,0 +1,22 @@
+
+
+ test
+
diff --git a/test/specs/config.spec.js b/test/specs/config.spec.js
index 660aafabc..c66ab40a6 100644
--- a/test/specs/config.spec.js
+++ b/test/specs/config.spec.js
@@ -85,9 +85,7 @@ describeWithShallowAndMount('config', mountingMethod => {
localVue
})
expect(wrapper.vm.prop1).to.equal('example')
- wrapper.setProps({
- prop1: 'new value'
- })
+ wrapper.vm.prop1 = 'new value'
expect(console.error).calledWith(sandbox.match('[Vue warn]'))
})
})
diff --git a/test/specs/wrapper/setProps.spec.js b/test/specs/wrapper/setProps.spec.js
index de74807dd..29b38c905 100644
--- a/test/specs/wrapper/setProps.spec.js
+++ b/test/specs/wrapper/setProps.spec.js
@@ -1,6 +1,7 @@
import { compileToFunctions } from 'vue-template-compiler'
import ComponentWithProps from '~resources/components/component-with-props.vue'
import ComponentWithWatch from '~resources/components/component-with-watch.vue'
+import ComponentWithWatchImmediate from '~resources/components/component-with-watch-immediate.vue'
import { describeWithShallowAndMount, vueVersion } from '~resources/utils'
import { itDoNotRunIf } from 'conditional-specs'
import Vue from 'vue'
@@ -244,6 +245,17 @@ describeWithShallowAndMount('setProps', mountingMethod => {
expect(wrapper.vm.propA).to.equal('value')
})
+ it('correctly sets props in async mode when component has immediate watchers', async () => {
+ const wrapper = mountingMethod(ComponentWithWatchImmediate, {
+ sync: false
+ })
+
+ const prop1 = 'testest'
+ wrapper.setProps({ prop1 })
+ await Vue.nextTick()
+ expect(wrapper.vm.prop1).to.equal(prop1)
+ })
+
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('