'Cannot access emit property while testing click event on Vue 3
I'm new to testing and I'm trying to test a component with Vue test-utils, but I'm having trouble when I try to test a click on a imported component.
This is my test file:
import { Table, Input } from 'ant-design-vue';
import { CheckOutlined, EditOutlined } from '@ant-design/icons-vue';
import { shallowMount } from '@vue/test-utils';
let wrapper;
beforeEach(() => {
wrapper = shallowMount(TableEditable, {
global: {
components: {
'a-table': Table,
'a-input': Input,
'check-outlined': CheckOutlined,
'edit-outlined': EditOutlined,
}
},
emits: ['edit', 'save'],
props: {
tableData: {
"data":[
{"id":"0","monday":"0"}],
"columns":[
{"title":"Mon","dataIndex":"monday","slots":{"customRender":"monday"}}]
},
dataSrc: [{"id":"0","monday":"0","tuesday":"0","wednesday":"0","thursday":"0","friday":"0","saturday":"9","sunday":"10","key":"0"}]
}
})
})
describe('first test', () => {
it('first test: check if theres a class name', () => {
expect(wrapper.classes()).toContain('tableEditable')
})
it('click and emit buttons', async () => {
await wrapper.findComponent({ref: 'edit-outlined'})
await wrapper.trigger('click')
expect(wrapper.emitted()).toHaveProperty('edit')
})
})
This is my component:
<template>
<a-table bordered :data-source="dataSrc" :columns="tableData.columns" :pagination="false" class="tableEditable">
<template #title>
<div class="formLayoutCrud">
<p>{{this.title}}</p>
<input-multiple-button :name="'buttonOptions'" :value="'percentage'" :options="this.buttonOptions"> </input-multiple-button>
</div>
</template>
<template v-for="col in this.editableCells" #[col]="{ column, text, record }" :key="col">
<div class="editable-cell">
<div v-if="editableTableData[record.key + '|' + column.key] !== undefined" class="editable-cell-input-wrapper">
<a-input v-model:value="editableTableData[record.key + '|' + column.key]" @pressEnter="save(record.key, column.key)" type="number" />
<check-outlined class="editable-cell-icon-check" @click="save(record.key, column.key)" />
</div>
<div v-else class="editable-cell-text-wrapper">
{{ text || ' ' }}
<edit-outlined class="editable-cell-icon" @click="edit(record.key, column.key)" />
</div>
</div>
</template>
</a-table>
</template>
<script>
import { CheckOutlined, EditOutlined } from '@ant-design/icons-vue';
import InputMultipleButton from '@/components/crudForm/InputMultipleButton.vue';
export default {
name: 'TableEditable',
props: {
title: String,
buttonOptions: Array,
editableCells: Array,
tableData: Object,
dataSrc: Array,
editableDataProp: Object
},
emits: ['edit', 'save'],
components: {
CheckOutlined,
EditOutlined,
InputMultipleButton
},
data(){
return {
editableTableData: this.editableDataProp
}
},
methods: {
edit(row, column) {
this.$emit('edit', row, column)
},
save(row, column) {
this.$emit('save', row, column)
}
}
}
</script>
<style>
And this is the error I get when I run npm test
> vue-cli-service test:unit "TableEditable.spec.js"
FAIL tests/unit/components/crudForm/TableEditable.spec.js
checkbox first tests
✓ first test: check if theres a class name (18ms)
✕ click and emit buttons (7ms)
● checkbox first tests › click and emit buttons
expect(received).toHaveProperty(path)
Expected path: "edit"
Received path: []
Received value: {"click": [[{"isTrusted": false}]]}
38 | // await wrapper.vm.$nextTick()
39 | await wrapper.trigger('click')
> 40 | expect(wrapper.emitted()).toHaveProperty('edit')
| ^
41 |
42 | })
43 | })
at Object.<anonymous> (tests/unit/components/crudForm/TableEditable.spec.js:40:39)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 4.653s
Ran all test suites matching /TableEditable.spec.js/i.
As I said, sorry if this is a simple error but I'm starting to learn tests so I don't have a lot of experience. If someone needs more information please let me know. Thanks in advance!
Solution 1:[1]
As far as I can tell expect(wrapper.emitted()).toHaveProperty('edit') should work.
So I think the issue is that the click is not working as you expect
you have
await wrapper.findComponent({ref: 'edit-outlined'})
await wrapper.trigger('click')
which will
- find the
edit-outlinedbutton in the wrapper - click on the component/wrapper (NOT the button)
to fix that, you can try chaining it like this:
await wrapper
.findComponent({ref: 'edit-outlined'})
.trigger('click');
The trigger here is assigned to the result of findComponent
Update
I believe wrapper.findComponent({ref: 'edit-outlined'}) is not finding the component. When using ref it will look for components that have that value in the ref attribute.
you have
<div v-else class="editable-cell-text-wrapper">
{{ text || ' ' }}
<edit-outlined class="editable-cell-icon" @click="edit(record.key, column.key)" />
</div>
edit-outlined is the name/type of the component, and not a ref.
you could change it to
<div v-else class="editable-cell-text-wrapper">
{{ text || ' ' }}
<edit-outlined ref="edit-outlined" class="editable-cell-icon" @click="edit(record.key, column.key)" />
</div>
which would put it into this.$refs internal object (this.$refs['edit-outlined'] specifically) which would make it accessible using wrapper.findComponent({ref: 'edit-outlined'}).
You should also be able to change the way you target that element which should make it work without changing the code you are testing.
findcomponent has three type you can pass as the selector argument.
{Component|ref|string} selector
If you only have one instance or EditOutlined, you can target that using the Component type like this:
const btn = wrapper.findComponent(EditOutlined);
expect(btn.exists()).toBe(true);
await btn.trigger('click');
also, it's a good idea to add these: expect(btn.exists()).toBe(true); They also act as a "sanity test" and make sure when you get an error that you are looking in the right place.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
