Vue3项目中VitestMock laravel-echo报错,求正确Mock方式
解决Vitest中Mock Laravel Echo的问题
一、针对模块导入的Laravel Echo
如果你的组件是通过import Echo from 'laravel-echo'引入使用的,正确的Mock方式是在测试文件顶部使用vi.mock的工厂函数,直接在工厂内部定义Mock对象(避免变量提升导致的错误):
// 测试文件顶部 import { vi } from 'vitest'; import Echo from 'laravel-echo'; vi.mock('laravel-echo', () => ({ default: { // 模拟private方法,返回自身以支持链式调用 private: vi.fn().mockReturnThis(), // 模拟listenToAll方法 listenToAll: vi.fn(), // 如果用到notification,同样模拟 notification: vi.fn().mockReturnThis() } }));
Mock完成后,组件调用Echo.private().listenToAll()不会报错,还能在测试用例中做断言验证:
import { mount } from '@vue/test-utils'; import YourComponent from '@/components/YourComponent.vue'; test('组件挂载时正确订阅私有频道', () => { const mockUserId = 123; mount(YourComponent, { global: { provide: { user: { id: mockUserId } } } }); // 断言private方法被传入正确参数调用 expect(Echo.private).toHaveBeenCalledWith(`user.${mockUserId}`); // 断言listenToAll方法被调用 expect(Echo.private().listenToAll).toHaveBeenCalled(); });
二、针对全局挂载的Laravel Echo
如果项目是把Echo挂载到window对象上(比如在resources/js/bootstrap.js中全局初始化),则需要在测试前后模拟/清理window.Echo:
import { vi } from 'vitest'; import { mount } from '@vue/test-utils'; import YourComponent from '@/components/YourComponent.vue'; beforeEach(() => { // 每个测试前初始化Mock的Echo window.Echo = { private: vi.fn().mockReturnThis(), listenToAll: vi.fn(), notification: vi.fn().mockReturnThis() }; }); afterEach(() => { // 测试后清理,避免污染其他用例 delete window.Echo; vi.clearAllMocks(); }); test('组件监听私有频道事件', () => { mount(YourComponent); expect(window.Echo.private).toHaveBeenCalled(); expect(window.Echo.private().listenToAll).toHaveBeenCalled(); });
错误原因分析
TypeError: default.private is not a function:直接调用vi.mock('laravel-echo')时,Vitest会生成空Mock模块,默认导出没有private等方法,组件调用自然报错。必须显式定义Mock对象的结构。Error: [vitest] There was an error when mocking a module...:vi.mock的工厂函数会被Vitest提升到文件最顶部执行,此时外部定义的mockEcho变量还未初始化,导致报错。因此必须在工厂函数内部直接定义Mock对象,不能引用外部变量。
内容的提问来源于stack exchange,提问作者Matt Larsuma
相关产品推荐
相关产品推荐

