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

Vitest+Unimport环境下模拟window全局依赖测试Laravel/Vue3项目

解决Laravel/Vue3项目中Vitest测试全局window依赖的问题

核心就是在测试环境里复刻bootstrap.js的逻辑——直接把mock好的axios、Echo、Pusher挂到window对象上,让组件不用额外导入就能用,和生产环境完全对齐。

具体步骤

  1. 创建全局依赖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等,用到就加
    };
    
  2. 让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之类的)按需加
      }
    });
    
  3. 测试组件时直接用,不用导入依赖
    现在组件里用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));
    });
    
  4. 动态调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:45:24