如何在Jest中测试未使用export的非模块类?
问题:非模块JS类无法在Jest中导入测试
我有一个MyClass.js文件,为了在HTML中同步加载它,我移除了export代码——因为带type="module"的<script>标签是异步加载的,这样改解决了应用里按需求使用该类的问题。
但现在没法在Jest测试套件里导入这个类,因为它不再是模块了,不管怎么弄MyClass最终都是undefined,我已经确认文件路径是对的。
已尝试的方法
- 读取代码用
eval()解析,但无效:const myClassCode = fs.readFileSync('./js/myClass.js', 'utf-8'); eval(myClassCode); - 基础的
import或require语句,这俩都要求文件是模块,所以没用。 - 用沙箱提取代码引入测试:
const classFileContent = fs.readFileSync(path.resolve(__dirname, '../MyClass.js'), 'utf-8'); // 创建带全局对象的新上下文 const context = { MyClass: undefined, }; vm.createContext(context); // 在创建的上下文中运行类文件代码 vm.runInContext(classFileContent, context); // 从上下文中获取类 const MyClass= context.MyClass;
可行解决方案
方案1:给测试环境单独添加导出(不修改生产逻辑)
在MyClass.js末尾添加一段条件导出代码,仅在Node/测试环境生效:
// MyClass.js原有代码 class MyClass { // 类的实现 } // 仅在Node环境下导出类,不影响浏览器全局变量 if (typeof module !== 'undefined' && module.exports) { module.exports = MyClass; }
这样生产环境中它依然是全局可用的类,Jest里直接用const MyClass = require('./MyClass.js')就能导入,完全不破坏原有应用。
方案2:测试文件中手动挂载全局变量
如果不想改动原文件,可在测试文件里读取并执行代码,将类挂载到Node全局对象:
const fs = require('fs'); const path = require('path'); // 读取并执行文件,让类成为全局变量 eval(fs.readFileSync(path.resolve(__dirname, '../MyClass.js'), 'utf-8')); // 从全局获取类 const MyClass = global.MyClass; // 测试示例 test('MyClass实例化正常', () => { const instance = new MyClass(); expect(instance).toBeInstanceOf(MyClass); });
注意:如果原代码中是直接声明class MyClass,在Node环境执行后会是模块级变量,不会自动到global。这时候需要调整原代码,用globalThis挂载类(兼容浏览器和Node):
// MyClass.js修改为 globalThis.MyClass = class MyClass { // 类的实现 };
方案3:用Jest配置预加载文件
在Jest配置文件(jest.config.js)中添加setupFiles,让Jest在所有测试前预加载MyClass.js,这样所有测试文件都能直接使用MyClass:
// jest.config.js module.exports = { setupFiles: ['./js/MyClass.js'] };
同样需要确保MyClass通过globalThis挂载为全局变量。
内容的提问来源于stack exchange,提问作者Jacob Chmielowiec
相关产品推荐
相关产品推荐

