-
Notifications
You must be signed in to change notification settings - Fork 668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(setprops): allowed for setProps to be synced with nextTick intervals #1618
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EDIT: ignore this, I forgot that this was overriding the method, so we know it's always returning a promise Additionally, the signature on setProps claims to potentially return void interface BaseWrapper {
setProps (props: object): Promise<void> | void
} so I'm getting warnings on ? this.setProps(data).then(`
maybe I'm missing something, I'm just trying to backport the fix for my project Janky backport function if anyone cares/**
* Bug: setProps doesn't play nice when there exists a watcher with immediate:true
* https://github.com/vuejs/vue-test-utils/pull/1618
*/
function setPropsForSure(
wrapper: Wrapper<CombinedVueInstance<any, any, any, any, any>>,
data: any,
) {
return new Promise(resolve => {
wrapper.setProps(data);
wrapper.vm.$nextTick().then(() => {
const isUpdated = Object.keys(data).every(key => {
return (
// $FlowIgnore : Problem with possibly null this.vm
wrapper.vm[key] === data[key] || wrapper.vm.$attrs[key] === data[key]
);
});
if (isUpdated) {
return resolve();
}
let result = setPropsForSure(wrapper, data);
if (result) {
result.then(() => resolve());
} else {
resolve();
}
});
});
} |
||
}) | ||
}) | ||
} catch (err) { | ||
throw err | ||
} finally { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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: '<div />', | ||
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 () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also added a deep equality test here to test the assign by reference in the code to make sure we don't get into some type of continual recursive loop. This looks to work as intended |
||
const callback = sinon.spy() | ||
const TestComponent = { | ||
template: '<div />', | ||
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', () => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this use
.every
?Otherwise, setting new props where one but not all of the new values is the same as the old could falsely signal that the update succeeded.