You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:05:12