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

Vue3+Vitest+Vue Test Utils检测组件函数调用:已defineExpose仍失效

解决Vue3 script setup组件Vitest测试中函数Spy检测失败的问题

问题分析

你遇到的问题由三个核心原因导致:

  • 测试代码中组件名称拼写错误,导致挂载了错误的组件
  • 测试环境未配置Vue I18n,组件初始化失败
  • Spy创建时机晚于组件初始渲染时的函数调用,无法捕捉到初始调用

解决方案

1. 修正组件名称拼写错误

确保测试中导入和挂载的组件名称与实际组件文件名一致:

// 正确导入组件
import DocumentDiscardModal from './DocumentDiscardModal.vue';

// 挂载时使用正确的组件名
const wrapper = mount(DocumentDiscardModal, {
  // ...后续配置
});

2. 配置测试用Vue I18n实例

组件依赖vue-i18n,测试环境必须提供对应的实例才能正常初始化:

import { createI18n } from 'vue-i18n';
import { mount } from '@vue/test-utils';
import DocumentDiscardModal from './DocumentDiscardModal.vue';

// 创建测试用的国际化实例
const testI18n = createI18n({
  locale: 'en',
  messages: {
    en: {
      select_an_option: 'Select an option',
      discard_document: 'Discard Document',
      discard_document_argument: 'Please select a reason for discarding.',
      wrong_document: 'Wrong Document',
      quality_issue: 'Quality Issue',
      other: 'Other',
      cancel: 'Cancel',
      discard: 'Discard'
    }
  }
});

3. 捕捉初始渲染时的函数调用

要检测组件初始渲染时getOptions的调用,需要在挂载前就将函数替换为Spy:

describe('DocumentDiscardModal.vue', () => {
  let getOptionsSpy: vi.SpyInstance;

  // 提前mock组件,注入Spy
  vi.mock('./DocumentDiscardModal.vue', async () => {
    const originalComponent = await vi.importActual('./DocumentDiscardModal.vue');
    
    // 创建Spy并预设返回值
    getOptionsSpy = vi.fn(() => [
      { id: '0', label: 'Select an option', disabled: true },
      { id: '1', label: 'Wrong Document' },
      { id: '2', label: 'Quality Issue' },
      { id: '3', label: 'Other' }
    ]);

    return {
      ...originalComponent,
      // 重写setup函数,替换目标函数为Spy
      setup(props: any, ctx: any) {
        const originalSetup = originalComponent.setup as (props: any, ctx: any) => any;
        const setupResult = originalSetup(props, ctx);
        
        setupResult.getOptions = getOptionsSpy;
        return setupResult;
      }
    };
  });

  test('getOptions should be called on initial render', () => {
    // 挂载组件,初始渲染会调用Spy
    mount(DocumentDiscardModal, {
      global: {
        plugins: [testI18n]
      },
      props: {
        id: 'document-discard-modal',
        isOpen: true,
      },
    });

    // 验证Spy被调用
    expect(getOptionsSpy).toHaveBeenCalled();
  });
});

替代方案(检测重新渲染时的调用)

如果不想使用vi.mock,可挂载组件后创建Spy并强制重新渲染:

describe('DocumentDiscardModal.vue', () => {
  test('getOptions should be called on re-render', () => {
    const wrapper = mount(DocumentDiscardModal, {
      global: {
        plugins: [testI18n]
      },
      props: {
        id: 'document-discard-modal',
        isOpen: true,
      },
    });

    // 创建Spy
    const getOptionsSpy = vi.spyOn(wrapper.vm, 'getOptions');
    
    // 强制组件重新渲染,触发函数调用
    wrapper.vm.$forceUpdate();

    // 验证Spy被调用
    expect(getOptionsSpy).toHaveBeenCalled();
  });
});

内容的提问来源于stack exchange,提问作者Ricardo de Vries

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 04:14:57