使用proxyquire搭配ES6 import时父上下文不可用的解决方法
问题:ES6模块环境下使用proxyquire mock依赖时报错
TypeError: Cannot read properties of undefined (reading 'require') 待测试文件 migration_repository.js
import {getDatabaseName} from "./maria_db_connector" export default class MigrationRepository { getExistingVersions() { return getDatabaseName(); } }
被mock的模块 maria_db_connector.js
export function getDatabaseName() { return process.env.KOA_DATASOURCE_DATABASE; }
当前测试代码
import MigrationRepository from './migration_repository.js' import proxyquire from 'proxyquire'; const proxy = proxyquire.noCallThru(); describe('MigrationRepository', function () { beforeEach(function () { proxy.load('./migration_repository.js', { './maria_db_connector.js': { getDatabaseName: function () { return "test" }, } }) }); }
错误信息
运行命令 mocha *spec.js 时出现以下错误:
TypeError: Cannot read properties of undefined (reading 'require')
报错对应的代码行:
return this._withoutCache(this._parent, stubs, request, this._parent.require.bind(this._parent, request))
环境信息
devDependencies:
"devDependencies": { "mocha": "^10.2.0", "proxyquire": "^2.1.3", "sinon": "^15.0.2" }
Node.js版本:v18.15.0
解决方案
问题根源是proxyquire默认适配CommonJS模块,直接在ES6模块(使用import/export)环境下调用proxy.load会因缺少CommonJS的require上下文报错。针对ES6模块环境,需调整测试写法:
方案1:使用proxyquire适配ES模块的正确写法
不要提前用import导入待测试模块,完全通过proxyquire加载并mock依赖,同时声明ES模块标识:
import proxyquire from 'proxyquire'; const proxy = proxyquire.noCallThru(); import assert from 'assert'; describe('MigrationRepository', function () { let MigrationRepository; beforeEach(function () { // 通过proxyquire加载目标模块并mock依赖 MigrationRepository = proxy('./migration_repository.js', { './maria_db_connector.js': { getDatabaseName: () => "test", esModule: true // 声明被mock的模块是ES模块 } }).default; // ES模块默认导出需访问.default属性 }); it('should return test database name', function () { const repo = new MigrationRepository(); const result = repo.getExistingVersions(); assert.strictEqual(result, "test"); }); });
方案2:确保Mocha支持ES模块(可选)
如果你的package.json中没有设置"type": "module",运行测试时需添加模块加载器参数:
mocha --loader esm *spec.js
Node.js 18+已原生支持ES模块,若package.json包含"type": "module",此步骤可省略。
关键注意事项
- 禁止提前用
import导入待测试模块,否则Node.js原生加载器会缓存模块,导致mock不生效。 - 对ES模块进行mock时,必须在stub对象中添加
esModule: true,否则proxyquire无法正确解析导出结构。 - 通过proxyquire获取ES模块的默认导出时,必须访问
.default属性,这是ES模块转CommonJS兼容层的规范要求。
内容的提问来源于stack exchange,提问作者piperRyan
相关产品推荐
相关产品推荐

