Vue3+Jest+Vue-test-utils如何测试async/await后的函数调用?
Vue3异步函数后调用函数的单元测试解决方案
问题背景
正在为Vue3组件实现100%单元测试覆盖率,遇到核心问题:无法测试onMounted中async/await Promise之后调用的setCounters函数。技术栈为Vue3、Pinia、i18n、Jest、Vue-test-utils。
组件核心代码
setup(props) { const { t } = useI18n(); const activeTab = ref(0); const scale = computed(() => props?.data?.policyConfig?.scales); const counters = ref([]); const { getDocumentsProcessedCount } = useAnalysis(); const { getConfigDomains, parseDomainLabel, parseDomainIcon, } = useDomains(); const getRulesCounter = () => ({ label: t('module.analysis.result.counter.rules.label'), count: props?.data?.policyConfig?.rules?.length, icon: 'list-resumo', }); const getDocumentsCounter = () => { const domainId = props?.data?.policyConfig?.domainId; return { label: parseDomainLabel(domainId), count: getDocumentsProcessedCount(props?.data?.processSummary), icon: parseDomainIcon(domainId), }; }; const loading = reactive({ scale: false, }); const setCounters = () => { counters.value = [ getRulesCounter(), getDocumentsCounter(), ]; }; const loadData = async () => { await getConfigDomains(); setCounters(); }; onMounted(() => { loadData(); }); return { activeTab, counters, scale, loading, getRulesCounter, getDocumentsCounter, loadData, setCounters, }; },
当前测试代码
it('Should loadData call setCounters', async () => { const spy = jest.spyOn(wrapper.vm, 'setCounters'); wrapper.vm.loadData(); await wrapper.vm.$nextTick(); await flushPromises(); expect(spy).toHaveBeenCalled(); });
问题原因
测试未正确等待loadData的异步流程完成,且getConfigDomains的mock未返回resolved状态的Promise,导致await语句未正确触发后续的setCounters调用。
解决方案
1. 确保getConfigDomains返回resolved Promise
修改mock配置,让getConfigDomains明确返回一个resolved的Promise:
export const mocks = { getConfigDomains: jest.fn().mockResolvedValue(domains.data.getConfigDomains), };
或者在测试文件中直接mockuseDomains组合式函数,同时处理依赖的辅助函数:
import { useDomains } from '@/composables/useDomains'; jest.mock('@/composables/useDomains', () => ({ useDomains: jest.fn().mockReturnValue({ getConfigDomains: jest.fn().mockResolvedValue(domains.data.getConfigDomains), parseDomainLabel: jest.fn().mockReturnValue('测试域名'), parseDomainIcon: jest.fn().mockReturnValue('domain-icon'), }), }));
2. 正确等待异步函数执行完成
修改测试代码,直接await loadData的执行,Jest会自动处理Promise等待:
it('Should loadData call setCounters', async () => { const spy = jest.spyOn(wrapper.vm, 'setCounters'); // 直接await异步函数完成 await wrapper.vm.loadData(); expect(spy).toHaveBeenCalled(); });
3. 测试onMounted中的自动调用
如果要验证组件挂载时自动触发的流程,可在mount后等待异步完成:
it('Should call setCounters after component mounts', async () => { const spy = jest.spyOn(wrapper.vm, 'setCounters'); // 等待onMounted中的loadData异步流程完成 await flushPromises(); expect(spy).toHaveBeenCalled(); });
补充说明
- 如果
setCounters依赖getConfigDomains返回的数据,可在mock中传入对应测试数据,确保parseDomainLabel和parseDomainIcon能正常返回预期值。 - 避免直接移除
async/await,这会破坏页面渲染的依赖逻辑,通过正确的mock和异步等待即可解决测试问题。
内容的提问来源于stack exchange,提问作者Wellington Roth
相关产品推荐
相关产品推荐

