1.0.0-beta.13
https://github.com/s-robertson/vtu-setdata
Create a new Vue component with the following criteria:
data() return an object containing an empty string, e.g. msgmsg is empty or not. E.g. hasMsg<input> in the component template that uses v-model, bound to msg<h1> in the component template that uses v-if, bound to hasMsg. This element must come AFTER the <input> in the templateNow write a unit test that:
shallow()setData and sets msg to a non-empty string<h1>Finally, run the unit test.
Calling setData will cause the component to re-render, making hasMsg be true and the test will pass.
Calling setData does _not_ cause the component to re-render. The unit test cannot find the <h1> element and fails:
FAIL tests/unit/HelloWorld.spec.js
HelloWorld.vue
✕ renders props.msg when passed (36ms)
● HelloWorld.vue › renders props.msg when passed
expect(received).toBe(expected) // Object.is equality
Expected value to be:
true
Received:
false
9 | wrapper.setData({ msg });
10 |
> 11 | expect(wrapper.contains('h1')).toBe(true);
12 | })
13 | });
14 |
at Object.<anonymous> (tests/unit/HelloWorld.spec.js:11:36)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.062s
Ran all test suites.
ERROR jest exited with code 1.
error Command failed with exit code 1.
What's interesting is that the order of the <input> and <h1> in the template matters. If the <h1> comes before the <input> the test will also pass.
You can also get the test to pass by forcefully updating the component via wrapper.vm.$forceUpdate(); after you've called setData.
I believe this has been fixed in the dev branch. The test case you provided passes.
Hi @eddyerburgh,
I switched to the dev branch in my example project, but am still seeing the unit test fail:
https://github.com/s-robertson/vtu-setdata/commit/7758fa2468489d815b99d69a7b895a95b1e45e73
That's because the dev branch did not have the updated built file.
I've released the fixes in 1.0.0-beta.14
@eddyerburgh
version: @vue/test-utils": "^1.0.0-beta.16"
I have a v-if pointing to a data property called errors.recordType on an element with the attribute data-test-id="record-type-error"
this fails...
const wrapper = mount(Modal)
wrapper.setData({ errors: { 'recordType': 'Error Message' } })
expect(wrapper.contains('[data-test-id="record-type-error"]')).toBe(true)
this does not...
const wrapper = mount(Modal)
wrapper.setData({ errors: { 'recordType': 'Error Message' } })
wrapper.vm.$forceUpdate()
expect(wrapper.contains('[data-test-id="record-type-error"]')).toBe(true)
Seems to not be fixed yet, unless I'm doing something wrong.
I have a similar problem as @An-AngryBear with 1.0.0-beta.16
<template>
<div>
<div>
<h2>Active stubs</h2>
<div
v-if="!activeStubs.length"
data-qa="no active stubs info"
>
No stubs enabled!
</div>
<table
v-else
data-qa="active stubs"
>
<tr
v-for="(stub, index) in activeStubs"
:key="index"
data-qa="active stub"
>
<td>{{ stub.url && stub.url.toString() }}</td>
<td>{{ stub.type }}</td>
<td>{{ stub.code }}</td>
</tr>
</table>
</div>
</div>
</template>
<script>
export default {
name: `NetworkTabContent`,
data() {
return {
activeStubs: [],
};
},
};
</script>
test(`It should render a table of active stubs.`, () => {
wrapper.setData({ activeStubs: [{}, {}] });
// Without the next line, the test fails because
// the component is not rerendered.
wrapper.vm.$forceUpdate();
expect(wrapper.contains(`[data-qa="active stubs"]`)).toBe(true);
expect(wrapper.findAll(`[data-qa="active stub"]`).length).toBe(2);
});
@maoberlehner Similarly I'm using v-if = "show" property, Initially it was set to false and I'm making it as true in a method. I've tried set the {show = true} using (setData) and called the particular method But got a _isDestroyed of undefined. please see the code below.
Test.vue
<template>
<div>some data</div>
<child v-if="show"></child>
</template>
<script>
export default {
name : 'test',
data() => {
return {
show: false
}
},
methods: {
toggleShow() {
this.show = !this.show
}
}
}
</script>
Test.test.js
describe('Methods ', () => {
const mountComponent = () => {
return shallowMount(Test, {
stubs: {
'child': true
}
})
}
it('test toggle', done => {
const wrapper = mountComponent()
wrapper.setData({ show: true });
wrapper.vm.$forceUpdate()
wrapper.vm.toggleShow()
expect(wrapper.vm.show).toBe(false) // should to toggle
done()
})
})
While running this test got following error ~~
Test.test.js › Methods › should call toggleShow
TypeError: Cannot read property '_isDestroyed' of undefined
57 | const wrapper = mountComponent()
> 58 | wrapper.setData({show: true})
| ^
59 | wrapper.vm.$forceUpdate()
60 | wrapper.vm.toggleShow()
61 | expect(wrapper.vm.show).toBe(false)
at destroy (node_modules/vue/dist/vue.runtime.common.js:4174:28)
at invokeDestroyHook (node_modules/vue/dist/vue.runtime.common.js:5741:59)
at removeVnodes (node_modules/vue/dist/vue.runtime.common.js:5757:11)
at VueComponent.patch [as __patch__] (node_modules/vue/dist/vue.runtime.common.js:6170:11)
at VueComponent.Vue._update (node_modules/vue/dist/vue.runtime.common.js:2668:19)
at VueComponent.vm._update (node_modules/@vue/test-utils/dist/vue-test-utils.js:2095:12)
at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.js:2786:10)
at Watcher.get (node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.run (node_modules/vue/dist/vue.runtime.common.js:3217:22)
at Watcher.update (node_modules/vue/dist/vue.runtime.common.js:3205:10)
at VueComponent.Vue.$forceUpdate (node_modules/vue/dist/vue.runtime.common.js:2689:19)
at updateChildComponent (node_modules/vue/dist/vue.runtime.common.js:2863:8)
at prepatch (node_modules/vue/dist/vue.runtime.common.js:4142:5)
at patchVnode (node_modules/vue/dist/vue.runtime.common.js:5923:7)
at updateChildren (node_modules/vue/dist/vue.runtime.common.js:5820:9)
at patchVnode (node_modules/vue/dist/vue.runtime.common.js:5934:29)
at VueComponent.patch [as __patch__] (node_modules/vue/dist/vue.runtime.common.js:6094:9)
at VueComponent.Vue._update (node_modules/vue/dist/vue.runtime.common.js:2668:19)
at VueComponent.vm._update (node_modules/@vue/test-utils/dist/vue-test-utils.js:2095:12)
at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.js:2786:10)
at Watcher.get (node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.run (node_modules/vue/dist/vue.runtime.common.js:3217:22)
at Watcher.update (node_modules/vue/dist/vue.runtime.common.js:3205:10)
at Dep.notify (node_modules/vue/dist/vue.runtime.common.js:695:13)
at Object.reactiveSetter [as show]
(node_modules/vue/dist/vue.runtime.common.js:1012:11)
at VueComponent.proxySetter [as show]
(node_modules/vue/dist/vue.runtime.common.js:3298:26)
at VueComponent.set [as $set] (node_modules/vue/dist/vue.runtime.common.js:1034:17)
at node_modules/@vue/test-utils/dist/vue-test-utils.js:1162:10
at Array.forEach (
at recursivelySetData (node_modules/@vue/test-utils/dist/vue-test-utils.js:1155:21)
at VueWrapper.setData (node_modules/@vue/test-utils/dist/vue-test-utils.js:1654:3)
at Object.setData (test/unit/views/tdi/HFE.test.js:59:15)
@narenderv7 Have you tried setting sync to false and using Vue.nextTick?
test('use Vue.nextTick', (done) => {
const wrapper = mount(TestComponent, { sync: false })
wrapper.trigger('click')
Vue.nextTick(() => {
expect(wrapper.text()).toBe('updated')
done()
})
})
I just came across this issue and I believe 1.0.0-beta.25 mitigates the original issue. I had a similar experience of not seeing a DOM update that would encourage a correct test assertion whereas now the assertion is returning the expected value.
I would kindly suggest @s-robertson to update to the latest version of the toolbelt and test it out. :+1:
I've just ugrade from 1.0.0-beta.22 to 1.0.0-beta.25 and get a similar issue.
modal-container.vue
<template>
<transition name="modal">
<div id="modal" class="modal__mask" v-if="config.show" :config="config">
<slot></slot>
</div>
</transition>
</template>
modal-container.specs.js
it('closes the modal when the close button is clicked', () => {
let modalConfig = { show: true }
const propsData = { config: modalConfig }
const wrapper = mount(ModalContainer, {
localVue,
propsData,
slots: {
default: 'Hello world',
},
})
const closeButton = wrapper.find('.modal__close')
closeButton.trigger('click')
expect(wrapper.isEmpty()).toBe(true)
})
This test fail, I still have to use wrapper.vm.forceUpdate() in order to make it pass.
This seems like a seperate issue @rlecellier , could you create a new issue with a reproduction in either a GitHub repo or codesandbox?
I've found that sometimes I have to use an async function and call await on setData and setProps
I ended up stubbing it, It worked for me
This seems to have regressed starting with 1.0.0-beta.30 and still broken in 1.0.0-beta.31. 1.0.0-beta.29 seems to work fine for me though.
Went back to 1.0.0-beta.29 as @onomojo said, and everything started working again.
The components for some reason were not* being updated after setData() for example.
@onomojo @rafaoliverce what do your tests look like? Are you using await wrapper.vm.$nextTick() in your tests? There was a large breaking
change in v30 to remove sync mode. This requires you to await for Vue to
finish the next event loop after each change that will affect the DOM.
Here are the current docs on it https://vue-test-utils.vuejs.org/guides/testing-async-components.html#updates-applied-by-vue
Yes, probably that's the cause of the problems.
Thanks @JessicaSachs !
Thanks @JessicaSachs !! You saved my day! I forget about the nextTick event always for Vue components.
Thanks @JessicaSachs , your comment saved my day, cheers!
Most helpful comment
@onomojo @rafaoliverce what do your tests look like? Are you using
await wrapper.vm.$nextTick()in your tests? There was a large breakingchange in v30 to remove sync mode. This requires you to await for Vue to
finish the next event loop after each change that will affect the DOM.
Here are the current docs on it https://vue-test-utils.vuejs.org/guides/testing-async-components.html#updates-applied-by-vue