在Jest中无法加载libsvm.js依赖的WASM文件,求解决方法
问题描述
我使用libsvm.js在浏览器中运行Python训练的模型,该库在Node和浏览器环境均能正常工作,但依赖的libsvm.wasm文件无法在Jest中加载。Jest模拟浏览器环境,却无法访问React项目public文件夹中的libsvm.wasm文件。
libsvm.wasm的路径由libsvm源码src目录下pre.js中的getCurrentPathBrowser函数处理,代码如下:
function getCurrentPathBrowser() { if ( typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope ) { return self.location.href; } var sc = document.getElementsByTagName('script'); for (var idx = 0; idx < sc.length; idx++) { var s = sc.item(idx); // 注:我的index.html里有匹配的script标签 // 这会让libsvm-js从localhost:3000/libsvm.wasm加载文件 if (s.src && s.src.match(/libsvm\.js$/)) { return s.src; } } return window.location.href; }
浏览器中该函数通过查找匹配/libsvm\.js$/的script标签获取路径,从而正确定位wasm文件。但Jest没有真实的本地服务,导致libsvm请求http://localhost/libsvm.wasm(不带端口),加载失败。我尝试过mock该函数,但它未被libsvm.js导出,无法直接mock,求最佳解决方法。
可行解决方案
方法1:注入模拟的script标签
既然函数依赖页面中的script标签获取路径,可在Jest的全局setup文件中提前注入符合匹配规则的script标签:
// jest.setup.js beforeAll(() => { const mockScript = document.createElement('script'); mockScript.src = 'http://localhost:3000/libsvm.js'; document.body.appendChild(mockScript); });
这样getCurrentPathBrowser函数就能找到该标签,返回正确路径,从而定位到public文件夹中的libsvm.wasm。
方法2:Mock整个libsvm模块
如果测试不需要实际运行libsvm的业务逻辑,可直接mock整个模块,避免加载wasm:
// 测试文件顶部 jest.mock('libsvm-js', () => ({ // 根据你实际使用的API编写模拟逻辑 SVM: jest.fn().mockImplementation(() => ({ loadModel: jest.fn().mockResolvedValue(true), predict: jest.fn().mockReturnValue(0) })) }));
方法3:修改Jest环境的window.location
直接修改Jest模拟环境中的window.location.href,让函数fallback时返回正确路径:
// 测试文件或setup文件中 beforeAll(() => { Object.defineProperty(window.location, 'href', { writable: true, value: 'http://localhost:3000/' }); });
此时函数找不到script标签时,会返回修改后的href,libsvm会请求http://localhost:3000/libsvm.wasm,对应到public文件夹内的文件。
方法4:用jest-webpack-resolver解析静态资源
若项目使用webpack打包,可配置Jest的resolver来正确解析wasm路径:
- 安装依赖:
npm install jest-webpack-resolver --save-dev - 在
jest.config.js中添加配置:
module.exports = { resolver: 'jest-webpack-resolver' };
Jest会遵循webpack的资源解析规则,找到public文件夹中的libsvm.wasm。
内容的提问来源于stack exchange,提问作者WebSight

