如何在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
相关产品推荐
相关产品推荐

