如何在CommonJS中动态导入ESModule版本的chai?
问题
Chai 5.1.2已转为ESModule,能否在CommonJS文件中继续使用?项目中仅将Chai作为单元测试的开发依赖,不想升级项目模块为ESModule。
尝试过以下几种方式,但都存在问题:
- 直接封装返回Promise的
expect函数,报错无法链式调用:
const expect = (...args) => import('chai').then((mod) => mod.expect(...args)); expect ('true').to.equal('false');
报错信息:
TypeError: Cannot read properties of undefined (reading 'equal')
原因是该expect返回的是Promise,不是Chai的断言对象,无法直接链式调用.to.equal。
- 将测试代码包裹在
import的回调中,可行但改动量大:
import('chai').then(chai => { expect = chai.expect; expect('true').to.equal('false'); });
需要把所有测试代码都放入回调,项目中大量expect语句,这种方式修改成本太高。
- 为每种断言类型封装单独函数,扩展性差:
const expectEqual = (arg1, arg2) => import('chai').then((mod) => mod.expect(arg1).to.equal(arg2));
要覆盖所有断言方法(如expect.to.be、expect.to.deep.equal等)需要编写大量重复函数,不现实。
更优解决方案
方案1:用require直接加载(Node.js >=14.13.0)
Node.js 14.13.0及以上版本支持在CommonJS中通过require加载ESModule,只需在末尾加上.default即可获取默认导出:
const chai = require('chai').default; const expect = chai.expect; // 原有测试代码无需改动,直接使用expect expect('true').to.equal('false');
这是最简便的方案,完全兼容原有测试逻辑,不需要额外修改。
方案2:使用顶层await(Node.js >=14.8.0)
如果你的Node.js版本支持顶层await(CommonJS文件需确保后缀为.cjs,且版本符合要求),可以在文件顶部一次性完成异步导入:
const chai = await import('chai'); const expect = chai.expect; // 后续所有测试代码正常使用expect,无需包裹 expect('true').to.equal('false');
这种方式也不需要修改原有测试代码,仅需在文件开头添加导入语句。
方案3:异步转同步(需额外依赖)
如果无法升级Node.js版本,可以使用deasync模块将异步导入转为同步(先执行npm install deasync --save-dev安装依赖):
const deasync = require('deasync'); let chaiInstance; import('chai').then(mod => { chaiInstance = mod; }); // 等待异步导入完成 deasync.loopWhile(() => !chaiInstance); const expect = chaiInstance.expect; // 正常使用断言 expect('true').to.equal('false');
这种方式需要额外安装依赖,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者Kerwen
相关产品推荐
相关产品推荐

