我已经使用Vuetify创建了一个Vue.js应用程序,现在正在尝试对一个包含Vuetify Data Table的组件进行单元测试。数据表是使用Axios从后端REST API填充的,当我运行应用程序时,它工作得很好,但是在我的单元测试(我用Jest模拟Axios )中,数据表永远不会填充
下面是我的组件的源代码
<template>
<v-container fluid>
<v-card>
<v-card-title>
Results
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="results"
:search="search"
:loading="loading"
loading-text="Loading results..."
:custom-sort="customSort"
>
<template v-slot:item.startTime="{item}">{{formatDate(item.startTime)}}</template>
<template v-slot:item.endTime="{item}">{{formatDate(item.endTime)}}</template>
</v-data-table>
</v-card>
</v-container>
</template>
<script>
import axios from 'axios';
import moment from 'moment';
function dateArrayToMoment(date) {
return moment()
.year(date[0])
.month(date[1])
.date(date[2])
.hour(date[3])
.minute(date[4]);
}
export default {
name: 'ResultsList',
data() {
return {
loading: true,
search: '',
headers: [
{ text: 'Task', align: 'start', sortable: false, value: 'title' },
{ text: 'State', value: 'state' },
{ text: 'Start Time', value: 'startTime' },
{ text: 'End Time', value: 'endTime' },
{ text: 'Result', value: 'resultMessage' }
],
results: []
};
},
mounted() {
this.loadResults();
},
methods: {
async loadResults() {
try {
let response = await axios.get('BACKEND_SERVER/results', {});
this.results = response.data;
this.loading = false;
// eslint-disable-next-line no-debugger
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
// you can handle different errors differently
// or just display an error message instead of your table using a <v-if> tag
// or navigate to an error page
}
},
formatDate(date) {
return dateArrayToMoment(date).format('YYYY-MM-DD hh:mm');
},
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index[0] == 'startTime' || index[0] == 'endTime') {
if (!isDesc[0]) {
return (
dateArrayToMoment(b[index]).toDate() -
dateArrayToMoment(a[index]).toDate()
);
} else {
return (
dateArrayToMoment(a[index]).toDate() -
dateArrayToMoment(b[index]).toDate()
);
}
}
});
return items;
}
}
};
</script>下面是测试组件的测试规范
import Vue from 'vue'
import Vuetify from 'vuetify'
import ResultsList from '@/components/ResultsList'
import { mount, createLocalVue } from '@vue/test-utils'
import axios from 'axios'
import flushPromises from 'flush-promises';
Vue.use(Vuetify)
const localVue = createLocalVue()
var results = [
{
'id': 1,
'state': 'COMPLETED',
'startTime': [2020, 4, 21, 19, 42],
'endTime': [2020, 4, 21, 19, 42],
'type': 'Example Scheduled Task',
'title': 'Example Scheduled Task at 2020-04-21 19:42:00',
'resultMessage': 'Task finished successfully'
},
{
'id': 2,
'state': 'COMPLETED',
'startTime': [2020, 4, 22, 13, 36],
'endTime': [2020, 4, 22, 13, 36],
'type': 'Example Scheduled Task',
'title': 'Example Scheduled Task at 2020-04-22 13:36:00',
'resultMessage': 'Task finished successfully'
},
{
'id': 3,
'state': 'COMPLETED',
'startTime': [2020, 4, 22, 13, 37],
'endTime': [2020, 4, 22, 13, 37],
'type': 'Example Scheduled Task',
'title': 'Example Scheduled Task at 2020-04-22 13:37:00',
'resultMessage': 'Task finished successfully'
}
];
// Use Jest to mock the Axios
jest.mock('axios');
describe('ResultsList.vue', () => {
let vuetify
beforeEach(() => {
vuetify = new Vuetify()
axios.get.mockResolvedValue(results);
})
it('should have a custom title and match snapshot', async () => {
const wrapper = mount(ResultsList, {
localVue,
vuetify,
propsData: {
title: 'Foobar',
},
})
await flushPromises()
// With jest we can create snapshot files of the HTML output
expect(wrapper.html()).toMatchSnapshot()
})
})如您所见,我使用Jest模拟Axios,因此它返回一些测试数据,并使用Jest验证快照。
问题是,快照不包含任何数据(测试或其他),尽管调用flushPromises来确保在拍摄快照之前解决了所有承诺。
这是快照。如您所见,数据表中没有显示任何数据,无论是测试还是其他。
// Jest Snapshot v1
exports[`ResultsList.vue should match snapshot 1`] = `
<div class="container container--fluid" title="Foobar">
<div class="v-card v-sheet theme--light">
<div class="v-card__title">
Results
<div class="spacer"></div>
<div class="v-input v-input--hide-details theme--light v-text-field v-text-field--single-line">
<div class="v-input__control">
<div class="v-input__slot">
<div class="v-text-field__slot"><label for="input-4" class="v-label theme--light" style="left: 0px; position: absolute;">Search</label><input id="input-4" type="text"></div>
<div class="v-input__append-inner">
<div class="v-input__icon v-input__icon--append"><i aria-hidden="true" class="v-icon notranslate mdi mdi-magnify theme--light"></i></div>
</div>
</div>
</div>
</div>
</div>
<div class="v-data-table theme--light">
<div class="v-data-table__wrapper">
<table>
<colgroup>
<col class="">
<col class="">
<col class="">
<col class="">
<col class="">
</colgroup>
<thead class="v-data-table-header">
<tr>
<th role="columnheader" scope="col" aria-label="Task" class="text-start"><span>Task</span></th>
<th role="columnheader" scope="col" aria-label="State: Not sorted. Activate to sort ascending." aria-sort="none" class="text-start sortable"><span>State</span><i aria-hidden="true" class="v-icon notranslate v-data-table-header__icon mdi mdi-arrow-up theme--light" style="font-size: 18px;"></i></th>
<th role="columnheader" scope="col" aria-label="Start Time: Not sorted. Activate to sort ascending." aria-sort="none" class="text-start sortable"><span>Start Time</span><i aria-hidden="true" class="v-icon notranslate v-data-table-header__icon mdi mdi-arrow-up theme--light" style="font-size: 18px;"></i></th>
<th role="columnheader" scope="col" aria-label="End Time: Not sorted. Activate to sort ascending." aria-sort="none" class="text-start sortable"><span>End Time</span><i aria-hidden="true" class="v-icon notranslate v-data-table-header__icon mdi mdi-arrow-up theme--light" style="font-size: 18px;"></i></th>
<th role="columnheader" scope="col" aria-label="Result: Not sorted. Activate to sort ascending." aria-sort="none" class="text-start sortable"><span>Result</span><i aria-hidden="true" class="v-icon notranslate v-data-table-header__icon mdi mdi-arrow-up theme--light" style="font-size: 18px;"></i></th>
</tr>
</thead>
<tbody>
<tr class="v-data-table__empty-wrapper">
<td colspan="5">No data available</td>
</tr>
</tbody>
</table>
</div>
<div class="v-data-footer">
<div class="v-data-footer__select">Rows per page:<div class="v-input v-input--hide-details v-input--is-label-active v-input--is-dirty theme--light v-text-field v-select">
<div class="v-input__control">
<div role="button" aria-haspopup="listbox" aria-expanded="false" aria-owns="list-17" class="v-input__slot">
<div class="v-select__slot">
<div class="v-select__selections">
<div class="v-select__selection v-select__selection--comma">10</div><input aria-label="$vuetify.dataTable.itemsPerPageText" id="input-17" readonly="readonly" type="text" aria-readonly="false" autocomplete="off">
</div>
<div class="v-input__append-inner">
<div class="v-input__icon v-input__icon--append"><i aria-hidden="true" class="v-icon notranslate mdi mdi-menu-down theme--light"></i></div>
</div><input type="hidden" value="10">
</div>
<div class="v-menu">
<!---->
</div>
</div>
</div>
</div>
</div>
<div class="v-data-footer__pagination">–</div>
<div class="v-data-footer__icons-before"><button type="button" disabled="disabled" class="v-btn v-btn--disabled v-btn--flat v-btn--icon v-btn--round v-btn--text theme--light v-size--default" aria-label="Previous page"><span class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate mdi mdi-chevron-left theme--light"></i></span></button></div>
<div class="v-data-footer__icons-after"><button type="button" disabled="disabled" class="v-btn v-btn--disabled v-btn--flat v-btn--icon v-btn--round v-btn--text theme--light v-size--default" aria-label="Next page"><span class="v-btn__content"><i aria-hidden="true" class="v-icon notranslate mdi mdi-chevron-right theme--light"></i></span></button></div>
</div>
</div>
</div>
</div>
`;发布于 2020-04-29 05:07:59
一些想法:在拍摄快照之前调用wrapper.vm.$nextTick()。
尝试使用localVue.use(Vuetify)而不是Vue.use()
https://stackoverflow.com/questions/61484502
复制相似问题