So I've created a vue component and I am using vue test utils to test it. The component allows a user to upload a file which updates an array which is emitted through the input (code shown below) that the user can then access. A new file upload will add to the array and not replace.
What's meant to happen:
I upload the first file and the emitted input event shows that one file; I then upload the second file and the emitted input event shows that file and the first one.
What does happen:
I upload the first file and the emitted input event shows that one file; I then upload the second file but the emitted input only shows the second file.
I'm not sure what is going on here as when I run tests in my browser and console the computed files I see that both files are in the array after doing the same process that my test is doing. I thought it was to do with it not updating fast enough so I added the wait for the next tick but with no luck. Is this a bug or is there something I'm not understanding about the events in my tests? Thanks for any help.
<template>
<input type="file" @change="handle"/>
</template>
<script>
export default {
props: {
value: {
type: Array,
required: false,
default() {
return []
}
}
},
method: {
handle(e) {
const files = e.target.files;
var newFiles = [];
for (var i = 0; i < files.length; i++) {
newFiles.push(files[i])
}
this.files = this.files.concat(newFiles)
}
},
computed: {
files: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
it('can add to array', async () => {
const files = [
{
name: 'image.png',
size: 20000000,
type: 'image/png',
},
{
name: 'image.jpg',
size: 20000,
type: 'image/jpeg',
},
]
const wrapper = mount(Component)
// Upload first file
wrapper.vm.handle({
target: {
files: [files[0]],
},
})
expect(wrapper.emitted().input[0]).toStrictEqual([
[files[0]]
]);
await wrapper.vm.$nextTick()
// Upload second file
wrapper.vm.handle({
target: {
files: [files[1]],
},
})
expect(wrapper.emitted().input[1]).toStrictEqual([files]);
}
I understand what has happened now. When the files array is changed in the component I'm emitting it but I'm not saving it anywhere when normally I would have a v-model saving it. As my tests don't simulate a v-model the computed files set value is an empty array. So I need to set the prop value in order to simulate that, I found that I can add a listener for the input event to update the value.
it('can add to array', async () => {
const files = [
{
name: 'image.png',
size: 20000000,
type: 'image/png',
},
{
name: 'image.jpg',
size: 20000,
type: 'image/jpeg',
},
]
const wrapper = mount(Component, {
listeners: {
// simulate v-model update
input: (val) => {
wrapper.setProps({ value: val });
}
}
})
// Upload first file
wrapper.vm.handle({
target: {
files: [files[0]],
},
})
expect(wrapper.emitted().input[0]).toStrictEqual([
[files[0]]
]);
await wrapper.vm.$nextTick()
// Upload second file
wrapper.vm.handle({
target: {
files: [files[1]],
},
})
expect(wrapper.emitted().input[1]).toStrictEqual([files]);
}
Another way to fix this is to save to a files array in the data of the component then call an update function to emit the new array.