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

如何在Jest中Mock项目上下文VSS库并解决类型错误

解决Jest测试中VSS库的Mock问题

问题描述

我在.ts文件中编写了Jest测试代码,已通过jest.spyOn Mock了appUtils中的getHostName等方法,但appUtils内部依赖项目上下文的VSS库(代码中通过const VSS_SDK = VSS;引用),运行测试时出现“ReferenceError: VSS is not defined”错误。尝试Mock VSS后,又触发类型错误:Type '() => { host: { authority: string; }; }' is not assignable to type '() => WebContext',提示WebContext缺少account等属性。

测试代码:

import { getBuildUrl } from '../../service/navigationService';

const appUtils = require('../../utils/appUtils');

describe('Report Title suite tests', () => {

let getHostNameStub = jest.spyOn(appUtils, 'getHostName')
let getOrganizationNameStub = jest.spyOn(appUtils, 'getOrganizationName')
let getProjectNameStub = jest.spyOn(appUtils, 'getProjectName')

  describe('returnBuildUrl', () => {
    getHostNameStub.mockReturnValue("HostNametest")
    getOrganizationNameStub.mockReturnValue("OrganizationTest")
    getProjectNameStub.mockReturnValue("ProjectNameTest")
    
    it('should display title and description without report URL', async () => {
      expect(getBuildUrl("IdTest")).toBeDefined();
      expect(getBuildUrl("IdTest")).toEqual("https://HostNametest/OrganizationTest/ProjectNameTest/_build/results?buildId=IdTest")
    });
  });
});

appUtils相关代码:

const VSS_SDK = VSS;

/**
 * return host name
 */
export function getHostName() {
  return VSS_SDK.getWebContext().host.authority;
}

WebContext接口定义:

interface WebContext {
    account: HostContext;
    /**
    * Information about the Collection used in the current request (may be null)
    */
    collection: HostContext;
    /**
    * Information about the current request context's host
    */
    host: ExtendedHostContext;
    /**
    * Information about the project used in the current request (may be null)
    */
    project: ContextIdentifier;
    /**
    * Information about the team used in the current request (may be null)
    */
    team: TeamContext;
    /**
    * Information about the current user
    */
    user: UserContext;
}

解决方案

方案一:完善全局VSS Mock,满足TypeScript类型要求

TypeScript会严格校验WebContext的结构,所以Mock的VSS对象必须返回完整符合接口定义的结构(缺失属性可以用空对象或默认值填充):

  1. 在测试文件顶部先声明全局VSS的类型,再Mock完整结构:
// 声明全局VSS类型,避免TS报错
declare global {
  var VSS: {
    getWebContext: () => WebContext;
  };
}

// Mock符合WebContext接口的完整结构,缺失属性用空对象占位
global.VSS = {
  getWebContext: () => ({
    account: {} as HostContext,
    collection: {} as HostContext,
    host: { authority: "HostNametest" } as ExtendedHostContext,
    project: {} as ContextIdentifier,
    team: {} as TeamContext,
    user: {} as UserContext,
  }),
};

// 注意:要在Mock之后再导入依赖模块
import { getBuildUrl } from '../../service/navigationService';
const appUtils = require('../../utils/appUtils');

这样既解决了VSS is not defined的报错,又能通过TypeScript的类型校验。

方案二:优化Mock逻辑,完全绕过VSS依赖

既然已经打算MockappUtils的方法,直接让这些Mock方法返回预期值即可,根本不需要触发内部的VSS调用,有两种实现方式:

方式1:调整Spy创建时机

确保在模块导入前就创建Spy,避免VSS代码被执行:

// 先导入appUtils并创建Spy
const appUtils = require('../../utils/appUtils');
const getHostNameStub = jest.spyOn(appUtils, 'getHostName').mockReturnValue("HostNametest");
const getOrganizationNameStub = jest.spyOn(appUtils, 'getOrganizationName').mockReturnValue("OrganizationTest");
const getProjectNameStub = jest.spyOn(appUtils, 'getProjectName').mockReturnValue("ProjectNameTest");

// 再导入测试目标模块
import { getBuildUrl } from '../../service/navigationService';

describe('Report Title suite tests', () => {
  describe('returnBuildUrl', () => {
    it('should display title and description without report URL', async () => {
      expect(getBuildUrl("IdTest")).toBeDefined();
      expect(getBuildUrl("IdTest")).toEqual("https://HostNametest/OrganizationTest/ProjectNameTest/_build/results?buildId=IdTest");
    });
  });

  // 测试完成后恢复原方法
  afterAll(() => {
    getHostNameStub.mockRestore();
    getOrganizationNameStub.mockRestore();
    getProjectNameStub.mockRestore();
  });
});

方式2:直接Mock整个appUtils模块

用jest.mock直接替换整个appUtils模块,彻底隔离VSS依赖:

import { getBuildUrl } from '../../service/navigationService';

// 直接Mock整个appUtils模块,指定方法返回值
jest.mock('../../utils/appUtils', () => ({
  getHostName: jest.fn().mockReturnValue("HostNametest"),
  getOrganizationName: jest.fn().mockReturnValue("OrganizationTest"),
  getProjectName: jest.fn().mockReturnValue("ProjectNameTest"),
}));

describe('Report Title suite tests', () => {
  describe('returnBuildUrl', () => {
    it('should display title and description without report URL', async () => {
      expect(getBuildUrl("IdTest")).toBeDefined();
      expect(getBuildUrl("IdTest")).toEqual("https://HostNametest/OrganizationTest/ProjectNameTest/_build/results?buildId=IdTest");
    });
  });
});

这种方式更简洁,完全不会触发appUtils内部的VSS相关代码,自然不会出现任何VSS相关的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:47:55