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

Jest运行测试时是否重定义全局Error变量导致实例断言失败?

问题描述

编写的数据库连接前置测试用例如下:

beforeAll(async () => {
  try {
    await db.connect();
  } catch(e: any) {
    expect(e).toBeInstanceOf(Error);
  }
});

测试运行失败,抛出反常错误:断言两侧打印的构造函数均为Error,但实例类型判断未通过:

expect(received).toBeInstanceOf(expected)

Expected constructor: Error
Received constructor: Error

项目相关配置如下:

jest.config.js

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
  preset:                 "ts-jest",
  testEnvironment:        "node",
  testPathIgnorePatterns: ["/node_modules/"]
};

package.json 相关片段

{
  "devDependencies": {
    "@types/jest": "28.1.3",
    "@types/node": "18.0.0",
    "jest": "28.1.1",
    "ts-jest": "28.0.5",
    "ts-node": "10.8.1",
    "typescript": "4.7.4",
  },
  "scripts": {
    "coverage": "jest --coverage",
    "test": "jest",
  }
}

tsconfig.json

{
  "compilerOptions": {
    "alwaysStrict": true,
    "esModuleInterop": true,
    "moduleResolution": "Node",
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "strict": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "target": "ESNext"
  },
  "exclude": ["*.d.ts"],
  "include": ["*.ts", "test/*.ts"]
}
问题根因

这是Jest 28+配合ts-jest、tsconfig设置target: "ESNext"时的典型跨执行上下文(realm)问题:

  • Jest运行测试时,会通过Node的vm模块创建独立的沙箱执行环境,沙箱内的全局对象和Node原生全局对象完全隔离,沙箱内的Error构造函数和Node原生的Error构造函数是两个内存地址独立的不同函数,仅名称相同。
  • 当tsconfig.target设为ESNext时,ts-jest编译代码不会对内置原生类型做兼容处理,如果引入的db模块是在沙箱外(比如通过ts-node直接挂载到Node原生上下文)加载的,它抛出的错误是原生上下文的Error实例,用沙箱内的Error做instanceof判断自然会返回false,打印构造函数名时两边都显示为Error,就会出现题述的反常报错。
解决方案

按优先级推荐以下解决方式:

  • 调整TypeScript编译目标:将tsconfig中的target从ESNext改为稳定的ES版本(如ES2021),让ts-jest编译时自动处理内置类型的跨上下文兼容问题:
    {
      "compilerOptions": {
        "target": "ES2021"
      }
    }
    
  • 调整ts-jest配置:在jest.config.js中关闭ts-jest的模块隔离模式,避免编译时生成独立的全局构造函数引用:
    /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
    module.exports = {
      preset:                 "ts-jest",
      testEnvironment:        "node",
      testPathIgnorePatterns: ["/node_modules/"],
      globals: {
        'ts-jest': {
          isolatedModules: false
        }
      }
    };
    
  • 绕开instanceof判断:如果不想调整配置,可以修改断言逻辑,通过构造函数名、错误对象特征判断类型,避免跨上下文的instanceof失效问题:
    beforeAll(async () => {
      try {
        await db.connect();
      } catch(e: any) {
        expect(e.constructor.name).toBe('Error');
        // 可增加错误特征判断提升准确性
        expect(typeof e.message).toBe('string');
      }
    });
    
  • 全局Error对齐(不推荐):新增setup文件在测试启动前将沙箱内的Error替换为Node原生Error,该方法可能影响其他依赖沙箱隔离的测试逻辑:
    首先新建jest.setup.js:
    global.Error = Error;
    
    再在jest.config.js中引入该文件:
    module.exports = {
      // 其余原有配置
      setupFiles: ['./jest.setup.js']
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:48:19