Vitest+Unimport环境下模拟window全局依赖测试Laravel/Vue3项目
解决Laravel/Vue3项目中Vitest测试全局window依赖的问题
核心就是在测试环境里复刻bootstrap.js的逻辑——直接把mock好的axios、Echo、Pusher挂到window对象上,让组件不用额外导入就能用,和生产环境完全对齐。
具体步骤
创建全局依赖mock文件
在测试目录下新建一个脚本,比如tests/setup/mocks/globalDeps.js,专门用来模拟全局挂载:// 模拟axios的常用方法 window.axios = { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn() }; // 模拟Pusher构造函数(如果组件用到Pusher实例) window.Pusher = vi.fn().mockImplementation(() => ({ subscribe: vi.fn(), unsubscribe: vi.fn() // 按需添加Pusher实例的方法 })); // 模拟Laravel Echo的核心方法 window.Echo = { private: vi.fn().mockReturnValue({ listen: vi.fn(), stopListening: vi.fn() // Echo.private返回的实例方法按需添加 }), channel: vi.fn().mockReturnValue({ listen: vi.fn() }) // 其他Echo方法比如broadcast等,用到就加 };让Vitest自动加载这个mock脚本
修改vitest.config.js,把刚才的文件配置成测试前置脚本,确保每个测试用例运行前都执行它:import { defineConfig } from 'vitest/config'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', // 必须用jsdom环境才能模拟浏览器window setupFiles: ['./tests/setup/mocks/globalDeps.js'], // 指定前置脚本 // 其他测试配置(比如globals: true之类的)按需加 } });测试组件时直接用,不用导入依赖
现在组件里用Echo、axios的地方,测试时不会再报未定义,而且和生产环境写法完全一致:import { mount } from '@vue/test-utils'; import ChatComponent from '@/components/ChatComponent.vue'; test('组件初始化时订阅私有频道', () => { mount(ChatComponent); // 验证Echo.private是否被正确调用 expect(window.Echo.private).toHaveBeenCalledWith('chat.user.123'); // 验证listen方法是否绑定了指定事件 expect(window.Echo.private().listen).toHaveBeenCalledWith('NewMessage', expect.any(Function)); });动态调整mock适配不同测试场景
如果某个测试需要模拟具体的返回值或回调触发,直接修改window上的mock就行:test('收到消息时更新组件内容', async () => { // 自定义listen方法,模拟收到消息时触发回调 const mockListen = vi.fn((event, callback) => { setTimeout(() => callback({ data: 'Hello from test' }), 0); }); window.Echo.private.mockReturnValue({ listen: mockListen }); const wrapper = mount(ChatComponent); await vi.runAllTimers(); // 触发异步回调 // 验证组件是否正确渲染了消息 expect(wrapper.find('.message-content').text()).toBe('Hello from test'); });
为什么之前浏览器会报错?
之前你在组件里导入Echo,生产环境中bootstrap.js已经把初始化好的Echo挂到window了,组件里再导入会导致两个不同的Echo实例冲突——导入的是未初始化的空对象,自然没有private方法。现在测试和生产环境都不用导入,直接用window上的全局对象,就不会有这个问题了。
内容的提问来源于stack exchange,提问作者Matt Larsuma
相关产品推荐
相关产品推荐

