如何为Jest中通过vm.runInContext加载的代码收集覆盖率?
解决Jest覆盖率为空的问题
你的问题出在用vm.runInContext直接执行代码时,V8覆盖率工具无法追踪到这些脚本的执行情况——Jest的V8覆盖率是基于通过其模块加载机制处理的文件,而手动读文件用VM执行的代码不在这个追踪范围内。以下是两种可行的解决办法:
方法一:切换到Babel覆盖率提供商并调整代码加载方式
这种方法通过Babel将无模块的全局代码转换为可被Jest识别的模块,同时保留全局挂载的逻辑。
步骤1:安装依赖
npm install --save-dev @babel/core @babel/preset-env babel-jest
步骤2:修改jest.config.js
将覆盖率提供商切换为babel,并启用babel-jest转换:
module.exports = { clearMocks: true, collectCoverage: true, collectCoverageFrom: [ "src/**/*.js", ], coverageDirectory: "coverage", coverageProvider: "babel", // 切换到babel覆盖率 testEnvironment: "./jest.env.js", transform: { "^.+\\.js$": "babel-jest" // 用babel处理所有JS文件 }, };
步骤3:创建Babel配置文件(.babelrc)
添加预设和插件,将全局函数自动转为模块导出:
{ "presets": ["@babel/preset-env"], "plugins": [ // 把顶级全局函数/变量转为module.exports ["@babel/plugin-transform-modules-commonjs", { "allowTopLevelThis": true }] ] }
步骤4:修改自定义测试环境(jest.env.js)
不再用VM执行,而是通过require加载转换后的模块,并挂载到全局:
const NodeEnvironment = require('jest-environment-node').TestEnvironment; const path = require("path"); class CustomEnv extends NodeEnvironment { constructor(config, context) { super(config, context); this.loadContext(); } loadContext() { // 加载经Babel转换后的模块 const moduleExports = require(path.resolve('./src/index.js')); // 将模块导出的内容挂载到全局上下文 Object.assign(this.global, moduleExports); } } module.exports = CustomEnv;
方法二:保留V8覆盖率,调整VM执行方式(需Jest支持)
如果不想切换到Babel,可以尝试让V8覆盖率工具识别VM中的脚本。修改jest.env.js,使用vm.Script并显式启用覆盖率追踪:
const NodeEnvironment = require('jest-environment-node').TestEnvironment; const fs = require('fs'); const vm = require("vm"); const path = require("path"); class CustomEnv extends NodeEnvironment { constructor(config, context) { super(config, context); this.loadContext(); } loadContext() { const filePath = path.resolve('./src/index.js'); const js = fs.readFileSync(filePath, 'utf8'); // 创建VM脚本时启用覆盖率选项 const script = new vm.Script(js, { filename: filePath, displayErrors: true, coverage: true // 显式开启V8覆盖率追踪 }); const context = vm.createContext(this.global); script.runInContext(context); Object.assign(this.global, context); } } module.exports = CustomEnv;
注意:这种方法依赖V8的coverage选项支持,部分Node.js版本或Jest版本可能存在兼容性问题,若无效建议优先使用方法一。
执行npm t后,即可正常生成覆盖率报告。
内容的提问来源于stack exchange,提问作者Gpack
相关产品推荐
相关产品推荐

