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

Vue+Jest环境下如何Mock window.gapi.load等谷歌授权方法?

解决Vue.js中Google Auth单元测试的Mock问题

我帮你梳理一下如何在Jest + vue-test-utils中Mock Google Auth的相关方法,确保你的npm run test:unit能顺利执行无报错。核心思路是提前Mock好window.gapi的整个结构,包括它的异步方法回调,同时覆盖组件内的自定义方法验证。

第一步:全局Mock window.gapi 对象

Google Auth的API都是挂载在window.gapi下的,所以我们需要在测试文件顶部先构建一个完整的Mock对象,关键是要处理gapi.load的异步回调(组件里依赖这个回调触发后续的auth2.init)。

// Login.spec.js 顶部
// 构建Mock的gapi对象
const mockGapi = {
  // 模拟gapi.load:直接调用传入的回调函数,模拟加载完成
  load: jest.fn((apiName, callback) => callback()),
  auth2: {
    // 模拟auth2.init,这里组件没用到返回值,用jest.fn()即可
    init: jest.fn()
  },
  signin2: {
    // 模拟signin2.render方法
    render: jest.fn()
  }
};

// 将Mock对象挂载到window上
window.gapi = mockGapi;

第二步:编写测试用例覆盖所有场景

接下来我们针对你需要验证的5个方法,编写对应的测试用例,同时确保组件挂载、方法调用的流程正确。

前置准备:Mock Vue Router

因为你的onSuccess方法里用到了$router.push,所以需要在挂载组件时注入Mock的路由实例:

import { mount } from '@vue/test-utils';
import Login from '@/components/Login.vue';
// 如果是Vue2,导入VueRouter并使用Vue.use(VueRouter)
import { createRouter, createWebHistory } from 'vue-router';

// 创建Mock路由
const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/homepage', name: 'Homepage' }]
});

// 重置Mock的辅助函数
beforeEach(() => {
  jest.clearAllMocks();
});

测试用例1:验证组件挂载后的流程

验证mounted钩子触发renderButton,进而调用init、gapi.load、auth2.init和signin2.render:

it('triggers Google Auth button rendering on mount', () => {
  const wrapper = mount(Login, {
    global: {
      plugins: [router] // 注入路由
    }
  });

  // 断言组件的renderButton方法被调用
  expect(wrapper.vm.renderButton).toHaveBeenCalled();
  // 断言gapi.load被调用,参数是'auth2'和回调函数
  expect(mockGapi.load).toHaveBeenCalledWith('auth2', expect.any(Function));
  // 断言auth2.init传入了正确的配置
  expect(mockGapi.auth2.init).toHaveBeenCalledWith({
    client_id: 'xyz',
    ux_mode: 'redirect'
  });
  // 断言signin2.render传入了正确的容器ID和配置
  expect(mockGapi.signin2.render).toHaveBeenCalledWith('my-signin2', expect.objectContaining({
    scope: 'profile email',
    width: 240,
    height: 50,
    longtitle: true,
    theme: 'dark',
    onsuccess: wrapper.vm.onSuccess,
    onfailure: wrapper.vm.onFailure
  }));
});

测试用例2:验证onSuccess方法的路由跳转

it('navigates to homepage on successful login', async () => {
  const wrapper = mount(Login, {
    global: {
      plugins: [router]
    }
  });

  // 调用onSuccess方法,随便传个GoogleUser对象(组件没用到它的属性)
  await wrapper.vm.onSuccess({});

  // 断言路由push被调用,目标路径是'/homepage'
  expect(router.push).toHaveBeenCalledWith('/homepage');
});

测试用例3:验证onFailure方法的日志输出

it('logs error message on login failure', () => {
  // Mock console.log,避免测试时真的打印日志
  const consoleLogMock = jest.spyOn(console, 'log').mockImplementation();
  const wrapper = mount(Login);

  wrapper.vm.onFailure();

  // 断言console.log输出了指定内容
  expect(consoleLogMock).toHaveBeenCalledWith('try again');
  // 恢复原有的console.log
  consoleLogMock.mockRestore();
});

测试用例4:验证renderButton的调用逻辑

it('calls init and signin2.render when renderButton is invoked', () => {
  const wrapper = mount(Login);
  // 清空之前的Mock调用记录
  jest.clearAllMocks();

  wrapper.vm.renderButton();

  // 断言init方法被调用
  expect(wrapper.vm.init).toHaveBeenCalled();
  // 断言signin2.render被调用
  expect(mockGapi.signin2.render).toHaveBeenCalled();
});

关键注意事项

  1. 异步回调处理:gapi.load是异步方法,组件里依赖它的回调触发auth2.init,所以Mock时必须主动调用传入的回调函数,否则后续逻辑不会执行。
  2. Mock重置:每个测试用例前用jest.clearAllMocks()重置Mock的调用记录,避免用例间的干扰。
  3. Vue版本适配:如果是Vue2,路由的注入方式是在挂载选项里传入router属性,而不是global.plugins,比如:
    const wrapper = mount(Login, { router });
    

现在把这些代码整合到你的Login.spec.js里,执行npm run test:unit应该就能顺利通过所有测试啦!

内容的提问来源于stack exchange,提问作者Rahul Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:32:47