-
Notifications
You must be signed in to change notification settings - Fork 668
Async watcher in some cases called twice after setProps. #1379
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
Comments
There were a lot of async changes with setProps, setData, and trigger in beta.30. Would you like to take a crack at this bug? |
Just wrote a unit test for this and it passes, the watcher's handler is called properly. it.only('runs the watcher only once', async () => {
const listener = () => Promise.resolve()
const spy = sinon.spy(listener)
const TestComponent = {
template: '<div/>',
props: ['prop1'],
watch: {
prop1: {
immediate: true,
handler: spy
}
}
}
const wrapper = mountingMethod(TestComponent)
await wrapper.vm.$nextTick()
expect(spy.callCount, 'To be called initially once').to.equal(1)
wrapper.setProps({
prop1: 'some Data'
})
await wrapper.vm.$nextTick()
expect(spy.callCount, 'to have been called an extra one time after using setProps').to.equal(2)
expect(spy.getCall(1).calledWith('some Data', undefined)).to.be.true
}) |
I have the following scenario which might be the same problem. If you guys have any idea how to work around it. And also if I can help with something else, just let me know. The code: AppSnackbar:
AppSnackbar.spec.js
The outcome is:
There is no place changing the visible value to false and this is the only test inside the spec. The version is: 1.0.0-beta.32 |
setProps with immediate watchers is buggy. For your test, the best practice
is to have visible be `true` initially on mount.
…On Wed, Apr 1, 2020 at 11:50 AM Guilherme Waess ***@***.***> wrote:
I have the following scenario which might be the same problem. If you guys
have any idea how to work around it.
And also if I can help with something else, just let me know.
The code:
AppSnackbar:
@component
export default class AppSnackbar extends Vue {
visiblityTimer: NodeJS.Timeout | null = null
@prop({ type: Boolean, required: true })
visible: boolean
@prop({ type: Number, default: 5000 })
timeout: number
@watch('visible', { immediate: true })
onVisibilityChange(visible, oldValue) {
console.log(
'AppSnackbar -> onVisibilityChange -> newValue',
visible,
oldValue
)
if (this.visiblityTimer) clearTimeout(this.visiblityTimer)
if (visible) {
this.visiblityTimer = setTimeout(() => {
this.$emit('hide')
}, this.timeout)
}
}
}
</script>
AppSnackbar.spec.js
it('should emit hide event after set timeout', async () => {
const wrapper = shallowMount(Snackbar, {
slots: {
default: 'foo bar',
},
propsData: {
visible: false,
timeout: 1000,
},
})
wrapper.setProps({ visible: true })
await wrapper.vm.$nextTick()
jest.advanceTimersByTime(1000)
expect(wrapper.emitted().hide).toBeDefined()
})
The outcome is:
1st console log from immediate
console.log packages/core/components/GlobalComponents/AppSnackbar.vue:30
AppSnackbar -> (newValue, oldValue) -> false undefined
2nd console log from setProps
console.log packages/core/components/GlobalComponents/AppSnackbar.vue:30
AppSnackbar -> (newValue, oldValue) -> true false
3rd console log ????????
console.log packages/core/components/GlobalComponents/AppSnackbar.vue:30
AppSnackbar -> (newValue, oldValue) -> false true
There is no place changing the visible value to false and this is the only
test inside the spec.
The version is: 1.0.0-beta.32
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1379 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAVL4BE5CC6XSJZ7SXNGOGTRKNPDBANCNFSM4J4L34SQ>
.
|
Version
1.0.0-beta.30
Reproduction link
https://github.com/motz-art/vue-test-utils-watcher-called-twice
Steps to reproduce
After opening repo run
What is expected?
After call to
setProps
component value watchhandler
should be called once.This will match behavior of such component in a real browser.
And console output should be like that:
As a result test will also pass.
What is actually happening?
After a call to
setProps
there is two calls to value watch handler, first with the value 'good' that is supplied insetProps
and second withundefined
.See console output:
As second call happens right before
Promise
is resolved, it setsdelayedValue
toundefined
and that leads to failed test.I don't know why but removing any of the
if
statements fixes the issue. As well as removingimmediate: true
from value watcher.Checked this test in
@vue/[email protected]
there is 3 calls to watch handler, so console output looks like:The text was updated successfully, but these errors were encountered: