From 9a3e6f96d71cba790cb2e7f9b918548c00758341 Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Sat, 1 Aug 2020 09:12:35 -0400 Subject: [PATCH] fix(setprops): allowed for setProps to be synced with nextTick intervals (#1618) * fix(setprops): allowed for setProps to be synced with nextTick intervals setProps in certain cases was being blown away by nextTick intervals. If the property is not up to date, setProps will be called again to sync the changes. fix #1419 * Update packages/test-utils/src/wrapper.js Co-authored-by: Bill Glesias Co-authored-by: Lachlan --- packages/test-utils/src/wrapper.js | 12 ++++- test/specs/wrapper/setProps.spec.js | 75 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/test-utils/src/wrapper.js b/packages/test-utils/src/wrapper.js index 6ea73b2cf..f93295386 100644 --- a/packages/test-utils/src/wrapper.js +++ b/packages/test-utils/src/wrapper.js @@ -711,7 +711,17 @@ export default class Wrapper implements BaseWrapper { // $FlowIgnore : Problem with possibly null this.vm this.vm.$forceUpdate() - return nextTick() + return new Promise(resolve => { + nextTick().then(() => { + const isUpdated = Object.keys(data).some(key => { + return ( + // $FlowIgnore : Problem with possibly null this.vm + this.vm[key] === data[key] || this.vm.$attrs[key] === data[key] + ) + }) + return !isUpdated ? this.setProps(data).then(resolve()) : resolve() + }) + }) } catch (err) { throw err } finally { diff --git a/test/specs/wrapper/setProps.spec.js b/test/specs/wrapper/setProps.spec.js index 635ffae66..ebd54cc17 100644 --- a/test/specs/wrapper/setProps.spec.js +++ b/test/specs/wrapper/setProps.spec.js @@ -187,6 +187,81 @@ describeWithShallowAndMount('setProps', mountingMethod => { await wrapper.setProps({ prop1 }) expect(wrapper.vm.prop2).to.equal(prop1) }) + + it('invokes watchers with immediate set to "true"', async () => { + const callback = sinon.spy() + const TestComponent = { + template: '
', + props: ['propA'], + mounted() { + this.$watch( + 'propA', + function() { + callback() + }, + { immediate: true } + ) + } + } + const wrapper = mountingMethod(TestComponent, { + propsData: { propA: 'none' } + }) + + expect(callback.calledOnce) + callback.resetHistory() + + await wrapper.setProps({ propA: 'value' }) + expect(wrapper.props().propA).to.equal('value') + expect(callback.calledOnce) + }) + + it('invokes watchers with immediate set to "true" with deep objects', async () => { + const callback = sinon.spy() + const TestComponent = { + template: '
', + props: ['propA'], + mounted() { + this.$watch( + 'propA', + function() { + callback() + }, + { immediate: true } + ) + } + } + const wrapper = mountingMethod(TestComponent, { + propsData: { + propA: { + key: { + nestedKey: 'value' + }, + key2: 'value2' + } + } + }) + + expect(callback.calledOnce) + callback.resetHistory() + + await wrapper.setProps({ + propA: { + key: { + nestedKey: 'newValue', + anotherNestedKey: 'value' + }, + key2: 'value2' + } + }) + expect(wrapper.props().propA).to.deep.equal({ + key: { + nestedKey: 'newValue', + anotherNestedKey: 'value' + }, + key2: 'value2' + }) + expect(callback.calledOnce) + }) }) it('props and setProps should return the same reference when called with same object', () => {