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

如何在Vitest中正确Mock Svelte组件并获取实例?

问题场景

我尝试使用vite-require插件在Vitest中Mock Svelte组件,编写了如下测试代码:

import Select from './__mocks__/select.svelte';

vi.mock('./select.svelte', () => {
  const c = require('./__mocks__/select.svelte').default;

  return {
    __esModule: true,
    default: vi.fn((args) => {
      return new c(args);
    }),
  };
});

beforeEach(() => {
  vi.restoreAllMocks();
});

describe('test', () => {
  test('test', () => {

    const { container } = render(ParentComponent, { });

    console.log(screen.debug(container));
    console.log(Select as any);
  });
});

父组件ParentComponent包含Select子组件,测试渲染后控制台能正确输出内容,说明Mock的Select组件已替换成功且编译正常。但打印Mock的Select时,其类型为[class Proxy<Select> extends ProxyComponent],并非实例,无法对其进行交互,也无法访问Vite的Mock对象。该代码参考了使用Jest的现有实现,请问如何在Vitest中实现预期效果?

解决方案

1. 在Mock中保存实例引用

直接在Mock的构造函数里保存实例,测试时就能直接访问实例进行交互:

import SelectMock from './__mocks__/select.svelte';

// 全局保存Mock组件实例,每次测试前重置
let mockSelectInstance;

vi.mock('./select.svelte', () => {
  return {
    __esModule: true,
    default: vi.fn((args) => {
      // 创建Mock组件实例并保存
      mockSelectInstance = new SelectMock(args);
      return mockSelectInstance;
    })
  };
});

beforeEach(() => {
  vi.clearAllMocks();
  mockSelectInstance = null;
});

describe('test', () => {
  test('test', () => {
    const { container } = render(ParentComponent, { });

    console.log(screen.debug(container));
    // 直接访问Mock组件实例
    console.log(mockSelectInstance);
    
    // 示例:调用组件方法、验证属性
    mockSelectInstance.handleChange('test-value');
    expect(mockSelectInstance.selectedValue).toBe('test-value');
    
    // 验证组件构造函数被调用
    expect(SelectMock).toHaveBeenCalled();
  });
});

2. 直接返回Mock组件并追踪构造

如果不需要包装成vi.fn,可以直接返回Mock组件,通过vi.spyOn追踪构造过程:

import SelectMock from './__mocks__/select.svelte';

vi.mock('./select.svelte', () => ({
  __esModule: true,
  default: SelectMock
}));

// 追踪Mock组件的构造函数
const selectConstructorSpy = vi.spyOn(SelectMock.prototype, 'constructor')
  .mockImplementation((args) => {
    const instance = new SelectMock(args);
    // 可在此添加实例的额外处理或保存逻辑
    return instance;
  });

beforeEach(() => {
  vi.clearAllMocks();
});

describe('test', () => {
  test('test', () => {
    render(ParentComponent, { });

    // 验证组件被实例化
    expect(selectConstructorSpy).toHaveBeenCalled();
    
    // 可选:在Mock组件内部通过全局变量暴露实例
    // 比如在select.svelte中添加:window.mockSelectInstance = this;
    // 测试中直接访问window.mockSelectInstance
  });
});

关键说明

  • 打印导入的Select得到Proxy是Svelte的内部机制:Svelte组件在实例化时会被包装成Proxy以实现响应式,你之前打印的是Mock的构造函数而非实例。
  • 通过在Mock构造函数中保存实例,或者在Mock组件内部暴露实例,就能在测试中直接进行交互。

内容的提问来源于stack exchange,提问作者Roger Far

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:30:59