在没有 babel 的情况下对原生 ES 模块的导出进行存根

Jim*_*Jin 13 node.js sinon ecmascript-6 ava es6-modules

我正在使用 AVA + sinon 来构建我的单元测试。由于我需要 ES6 模块并且我不喜欢 babel,因此我在整个项目中使用 mjs 文件,包括测试文件。我使用“--experimental-modules”参数来启动我的项目,并在测试中使用“esm”包。以下是我的ava配置和测试代码。

  "ava": {
    "require": [
      "esm"
    ],
    "babel": false,
    "extensions": [
      "mjs"
    ]
  },


// test.mjs
import test from 'ava';
import sinon from 'sinon';
import { receiver } from '../src/receiver';
import * as factory from '../src/factory';

test('pipeline get called', async t => {
  const stub_factory = sinon.stub(factory, 'backbone_factory');
  t.pass();
});
Run Code Online (Sandbox Code Playgroud)

但我收到错误消息:

  TypeError {
    message: 'ES Modules cannot be stubbed',
  }
Run Code Online (Sandbox Code Playgroud)

如何在没有 babel 的情况下存根 ES6 模块?

oli*_*ren 7

根据esm 包的创建者John-David Dalton 的说法,只能改变*.js文件的名称空间 -*.mjs文件被锁定。

这意味着 Sinon(以及所有其他软件)无法存根这些模块 - 正如错误消息所指出的那样。这里有两种方法可以解决这个问题:

  1. 只需将文件的扩展名重命名为.js即可使导出可变。这是侵入性最小的,因为默认情况下该mutableNamespace 选项处于启用esm状态。esm当然,这仅适用于您使用加载程序时。
  2. 使用专用的模块加载器来代理所有导入并用您喜欢的模块替换它们。

选项 2 的技术堆栈不可知术语是链接接缝- 本质上取代了 Node 的默认模块加载器。通常可以使用QuibbleESMockproxyquirerewire这意味着使用 Proxyquire 时上面的测试看起来像这样:

// assuming that `receiver` uses `factory` internally

// comment out the import - we'll use proxyquire
// import * as factory from '../src/factory';
// import { receiver } from '../src/receiver';

const factory = { backbone_factory: sinon.stub() };
const receiver = proxyquire('../src/receiver', { './factory' : factory });
Run Code Online (Sandbox Code Playgroud)

修改 proxyquire 示例以使用 Quibble 或 ESMock(两者都原生支持 ESM)应该很简单。