From 51822006f546e978ad6541f534235dad62b08276 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Thu, 25 Jan 2018 20:37:25 +0000 Subject: [PATCH 1/2] fix: update object in setProps --- src/wrappers/wrapper.js | 4 +++- test/unit/specs/mount/Wrapper/props.spec.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/wrappers/wrapper.js b/src/wrappers/wrapper.js index ba50316e3..b0389ca2e 100644 --- a/src/wrappers/wrapper.js +++ b/src/wrappers/wrapper.js @@ -452,14 +452,16 @@ export default class Wrapper implements BaseWrapper { if (!this.isVueComponent || !this.vm) { throwError('wrapper.setProps() can only be called on a Vue instance') } - Object.keys(data).forEach((key) => { // $FlowIgnore : Problem with possibly null this.vm if (this.vm._props) { this.vm._props[key] = data[key] + this.vm.$props[key] = data[key] + this.vm.$options.propsData[key] = data[key] } else { // $FlowIgnore : Problem with possibly null this.vm this.vm[key] = data[key] + this.vm.$options.propsData[key] = data[key] } }) diff --git a/test/unit/specs/mount/Wrapper/props.spec.js b/test/unit/specs/mount/Wrapper/props.spec.js index ff6e15f8a..974ed1d84 100644 --- a/test/unit/specs/mount/Wrapper/props.spec.js +++ b/test/unit/specs/mount/Wrapper/props.spec.js @@ -18,6 +18,20 @@ describe('props', () => { expect(wrapper.props()).to.eql({}) }) + it.only('should update after setProps', () => { + const prop1 = {} + const prop2 = 'val1' + const wrapper = mount(ComponentWithProps, { + propsData: { prop1, prop2 } + }) + + expect(wrapper.props()).to.eql({ prop1: {}, prop2: 'val1' }) + // setProps + wrapper.setProps({ prop2: 'val2' }) + expect(wrapper.vm.prop2).to.eql('val2') // pass + expect(wrapper.props()).to.eql({ prop1: {}, prop2: 'val2' }) // fail + }) + it('throws an error if called on a non vm wrapper', () => { const compiled = compileToFunctions('

') const p = mount(compiled).findAll('p').at(0) From cf95ff70de9d3e2a2cd2c5915665e5a2af28acfd Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Fri, 26 Jan 2018 20:53:30 +0000 Subject: [PATCH 2/2] fix: only run watchers for expressions that have changed in setData and setProps --- src/wrappers/vue-wrapper.js | 17 +++++++++---- src/wrappers/wrapper.js | 7 ++++-- test/unit/specs/mount/Wrapper/props.spec.js | 2 +- test/unit/specs/mount/Wrapper/setData.spec.js | 22 +++++++++++++++++ .../unit/specs/mount/Wrapper/setProps.spec.js | 24 +++++++++++++++++++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/wrappers/vue-wrapper.js b/src/wrappers/vue-wrapper.js index 925e79822..03b5afc02 100644 --- a/src/wrappers/vue-wrapper.js +++ b/src/wrappers/vue-wrapper.js @@ -4,7 +4,7 @@ import Wrapper from './wrapper' import addSlots from '../lib/add-slots' import cloneDeep from 'lodash/cloneDeep' -function update () { +function update (changedData) { // the only component made by mount() if (this.$_originalSlots) { this.$slots = cloneDeep(this.$_originalSlots) @@ -12,9 +12,18 @@ function update () { if (this.$_mountingOptionsSlots) { addSlots(this, this.$_mountingOptionsSlots) } - this._watchers.forEach(watcher => { - watcher.run() - }) + if (changedData) { + Object.keys(changedData).forEach((key) => { + // $FlowIgnore : Problem with possibly null this.vm + this._watchers.forEach((watcher) => { + if (watcher.expression === key) { watcher.run() } + }) + }) + } else { + this._watchers.forEach(watcher => { + watcher.run() + }) + } const vnodes = this._render() this._update(vnodes) this.$children.forEach(child => update.call(child)) diff --git a/src/wrappers/wrapper.js b/src/wrappers/wrapper.js index b0389ca2e..995342f3a 100644 --- a/src/wrappers/wrapper.js +++ b/src/wrappers/wrapper.js @@ -377,7 +377,7 @@ export default class Wrapper implements BaseWrapper { this.vm.$set(this.vm, [key], data[key]) }) - this.update() + this.update(data) } /** @@ -452,6 +452,9 @@ export default class Wrapper implements BaseWrapper { if (!this.isVueComponent || !this.vm) { throwError('wrapper.setProps() can only be called on a Vue instance') } + if (!this.vm.$options.propsData) { + this.vm.$options.propsData = {} + } Object.keys(data).forEach((key) => { // $FlowIgnore : Problem with possibly null this.vm if (this.vm._props) { @@ -465,7 +468,7 @@ export default class Wrapper implements BaseWrapper { } }) - this.update() + this.update(data) // $FlowIgnore : Problem with possibly null this.vm this.vnode = this.vm._vnode } diff --git a/test/unit/specs/mount/Wrapper/props.spec.js b/test/unit/specs/mount/Wrapper/props.spec.js index 974ed1d84..44fc176e9 100644 --- a/test/unit/specs/mount/Wrapper/props.spec.js +++ b/test/unit/specs/mount/Wrapper/props.spec.js @@ -18,7 +18,7 @@ describe('props', () => { expect(wrapper.props()).to.eql({}) }) - it.only('should update after setProps', () => { + it('should update after setProps', () => { const prop1 = {} const prop2 = 'val1' const wrapper = mount(ComponentWithProps, { diff --git a/test/unit/specs/mount/Wrapper/setData.spec.js b/test/unit/specs/mount/Wrapper/setData.spec.js index 0cf4f4926..f552252be 100644 --- a/test/unit/specs/mount/Wrapper/setData.spec.js +++ b/test/unit/specs/mount/Wrapper/setData.spec.js @@ -58,4 +58,26 @@ describe('setData', () => { const p = wrapper.find('p') expect(() => p.setData({ ready: true })).throw(Error, message) }) + + it('should not run watchers if data updated is null', () => { + const TestComponent = { + template: ` +
+
There is no message yet
+
{{ reversedMessage }}
+
+ `, + data: () => ({ + message: 'egassem' + }), + computed: { + reversedMessage: function () { + return this.message.split('').reverse().join('') + } + } + } + const wrapper = mount(TestComponent) + wrapper.setData({ message: null }) + expect(wrapper.text()).to.equal('There is no message yet') + }) }) diff --git a/test/unit/specs/mount/Wrapper/setProps.spec.js b/test/unit/specs/mount/Wrapper/setProps.spec.js index c0ebd818b..b9e4ee010 100644 --- a/test/unit/specs/mount/Wrapper/setProps.spec.js +++ b/test/unit/specs/mount/Wrapper/setProps.spec.js @@ -47,6 +47,30 @@ describe('setProps', () => { expect(info.args[0][0]).to.equal(prop1) }) + it('should not run watchers if prop updated is null', () => { + const TestComponent = { + template: ` +
+
There is no message yet
+
{{ reversedMessage }}
+
+ `, + computed: { + reversedMessage: function () { + return this.message.split('').reverse().join('') + } + }, + props: ['message'] + } + const wrapper = mount(TestComponent, { + propsData: { + message: 'message' + } + }) + wrapper.setProps({ message: null }) + expect(wrapper.text()).to.equal('There is no message yet') + }) + 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('

')