Skip to content

Commit 6689dbc

Browse files
authored
fix: update $props object in setProps (#381)
* fix: update object in setProps * fix: only run watchers for expressions that have changed in setData and setProps
1 parent 48928e1 commit 6689dbc

File tree

5 files changed

+81
-7
lines changed

5 files changed

+81
-7
lines changed

src/wrappers/vue-wrapper.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@ import Wrapper from './wrapper'
44
import addSlots from '../lib/add-slots'
55
import cloneDeep from 'lodash/cloneDeep'
66

7-
function update () {
7+
function update (changedData) {
88
// the only component made by mount()
99
if (this.$_originalSlots) {
1010
this.$slots = cloneDeep(this.$_originalSlots)
1111
}
1212
if (this.$_mountingOptionsSlots) {
1313
addSlots(this, this.$_mountingOptionsSlots)
1414
}
15-
this._watchers.forEach(watcher => {
16-
watcher.run()
17-
})
15+
if (changedData) {
16+
Object.keys(changedData).forEach((key) => {
17+
// $FlowIgnore : Problem with possibly null this.vm
18+
this._watchers.forEach((watcher) => {
19+
if (watcher.expression === key) { watcher.run() }
20+
})
21+
})
22+
} else {
23+
this._watchers.forEach(watcher => {
24+
watcher.run()
25+
})
26+
}
1827
const vnodes = this._render()
1928
this._update(vnodes)
2029
this.$children.forEach(child => update.call(child))

src/wrappers/wrapper.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ export default class Wrapper implements BaseWrapper {
377377
this.vm.$set(this.vm, [key], data[key])
378378
})
379379

380-
this.update()
380+
this.update(data)
381381
}
382382

383383
/**
@@ -452,18 +452,23 @@ export default class Wrapper implements BaseWrapper {
452452
if (!this.isVueComponent || !this.vm) {
453453
throwError('wrapper.setProps() can only be called on a Vue instance')
454454
}
455-
455+
if (!this.vm.$options.propsData) {
456+
this.vm.$options.propsData = {}
457+
}
456458
Object.keys(data).forEach((key) => {
457459
// $FlowIgnore : Problem with possibly null this.vm
458460
if (this.vm._props) {
459461
this.vm._props[key] = data[key]
462+
this.vm.$props[key] = data[key]
463+
this.vm.$options.propsData[key] = data[key]
460464
} else {
461465
// $FlowIgnore : Problem with possibly null this.vm
462466
this.vm[key] = data[key]
467+
this.vm.$options.propsData[key] = data[key]
463468
}
464469
})
465470

466-
this.update()
471+
this.update(data)
467472
// $FlowIgnore : Problem with possibly null this.vm
468473
this.vnode = this.vm._vnode
469474
}

test/unit/specs/mount/Wrapper/props.spec.js

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ describe('props', () => {
1818
expect(wrapper.props()).to.eql({})
1919
})
2020

21+
it('should update after setProps', () => {
22+
const prop1 = {}
23+
const prop2 = 'val1'
24+
const wrapper = mount(ComponentWithProps, {
25+
propsData: { prop1, prop2 }
26+
})
27+
28+
expect(wrapper.props()).to.eql({ prop1: {}, prop2: 'val1' })
29+
// setProps
30+
wrapper.setProps({ prop2: 'val2' })
31+
expect(wrapper.vm.prop2).to.eql('val2') // pass
32+
expect(wrapper.props()).to.eql({ prop1: {}, prop2: 'val2' }) // fail
33+
})
34+
2135
it('throws an error if called on a non vm wrapper', () => {
2236
const compiled = compileToFunctions('<div><p /></div>')
2337
const p = mount(compiled).findAll('p').at(0)

test/unit/specs/mount/Wrapper/setData.spec.js

+22
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,26 @@ describe('setData', () => {
5858
const p = wrapper.find('p')
5959
expect(() => p.setData({ ready: true })).throw(Error, message)
6060
})
61+
62+
it('should not run watchers if data updated is null', () => {
63+
const TestComponent = {
64+
template: `
65+
<div>
66+
<div v-if="!message">There is no message yet</div>
67+
<div v-else>{{ reversedMessage }}</div>
68+
</div>
69+
`,
70+
data: () => ({
71+
message: 'egassem'
72+
}),
73+
computed: {
74+
reversedMessage: function () {
75+
return this.message.split('').reverse().join('')
76+
}
77+
}
78+
}
79+
const wrapper = mount(TestComponent)
80+
wrapper.setData({ message: null })
81+
expect(wrapper.text()).to.equal('There is no message yet')
82+
})
6183
})

test/unit/specs/mount/Wrapper/setProps.spec.js

+24
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,30 @@ describe('setProps', () => {
4747
expect(info.args[0][0]).to.equal(prop1)
4848
})
4949

50+
it('should not run watchers if prop updated is null', () => {
51+
const TestComponent = {
52+
template: `
53+
<div>
54+
<div v-if="!message">There is no message yet</div>
55+
<div v-else>{{ reversedMessage }}</div>
56+
</div>
57+
`,
58+
computed: {
59+
reversedMessage: function () {
60+
return this.message.split('').reverse().join('')
61+
}
62+
},
63+
props: ['message']
64+
}
65+
const wrapper = mount(TestComponent, {
66+
propsData: {
67+
message: 'message'
68+
}
69+
})
70+
wrapper.setProps({ message: null })
71+
expect(wrapper.text()).to.equal('There is no message yet')
72+
})
73+
5074
it('throws an error if node is not a Vue instance', () => {
5175
const message = 'wrapper.setProps() can only be called on a Vue instance'
5276
const compiled = compileToFunctions('<div><p></p></div>')

0 commit comments

Comments
 (0)