能否在 Mocha 测试中使用 ES6 模块?

34

ES6、Windows 10 x64、Node.js 8.6.0、Mocha 3.5.3

在Mocha测试中使用ES6模块是否可行?我遇到了使用exportimport关键字的问题。

/* eventEmitter.js
 */

/* Event emitter. */
export default class EventEmitter{

    constructor(){

        const subscriptions = new Map();

        Object.defineProperty(this, 'subscriptions', {
            enumerable: false,
            configurable: false,
            get: function(){
                return subscriptions;
            }
        });
    }

    /* Add the event listener.
     * @eventName - the event name. 
     * @listener - the listener.
     */
    addListener(eventName, listener){
        if(!eventName || !listener) return false;
        else{
            if(this.subscriptions.has(eventName)){
                const arr = this.subscriptions.get(eventName);
                arr.push(listener);
            }
            else{
                const arr = [listener];
                this.subscriptions.set(eventName, arr);
            }
            return true;
        }
    }

    /* Delete the event listener.
     * @eventName - the event name. 
     * @listener - the listener.
     */
    deleteListener(eventName, listener){
        if(!eventName || !listener) return false;
        else{
            if(this.subscriptions.has(eventName)){
                const arr = this.subscriptions.get(eventName);
                let index = arr.indexOf(listener);

                if(index >= 0){
                    arr.splice(index, 1);
                    return true;
                }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
        }
    }

    /* Emit the event.
     * @eventName - the event name. 
     * @info - the event argument.
     */
    emit(eventName, info){
        if(!eventName || !this.subscriptions.has(eventName)) {
            return false;
        }
        else{
            for(let fn of this.subscriptions.get(eventName)){
                if(fn) fn(info);
            }
            return true;
        }
    }
}

Mocha测试:

/* test.js 
 * Mocha tests.
 */
import EventEmitter from '../../src/js/eventEmitter.js';

const assert = require('assert');

describe('EventEmitter', function() {
  describe('#constructor()', function() {
    it('should work.', function() {
        const em = new EventEmitter();
        assert.equal(true, Boolean(em));
    });
  });
});

我直接通过PowerShell控制台启动mocha。结果如下:

在此输入图片描述


1
https://mochajs.org/#about-babel - robertklep
http://jamesknelson.com/testing-in-es6-with-mocha-and-babel-6/ - winseybash
3
我认为重点是Node 8.6支持导入/导出而无需转译。但是,我不确定mocha是否允许使用--experimental-modules,这是必需的才能利用它,因此在它支持之前(或者直到支持稳定版),可能仍然需要进行转译。 - CodingIntrigue
4
我认为这不是重复的问题。现代浏览器已经原生支持ES模块,可以通过在浏览器中运行Mocha测试而无需使用Babel来实现。 - vitalets
8
时间已经过去了,现在可以使用 esm 模块来与 mocha 一起使用导入语法。 将其添加到您的依赖项中,然后只需使用 mocha -r esm 即可。 甚至不需要切换到 .mjs 扩展名。 - Feugy
3
这个问题并不是 https://stackoverflow.com/questions/46255387/unexpected-token-import-when-using-mocha-with-babel 的重复,因为后者与 Babel 有关,而这个问题则不是。 - Flimm
4个回答

33

Mocha从版本7.1.0开始(发布日期:2020年2月26日)支持ESM。详情请见链接

这需要Node 12.11.0或更高版本,并受到在Node中使用模块的当前限制/限制的约束:

  • 对于使用ES模块的源文件,您必须使用.mjs文件扩展名,或者在package.json中有 "type": "module"
  • 当从CommonJS模块进行import时,无法使用命名导入。
  • 本地的import语句必须显式包含.js文件扩展名。

等等。

更新的回答

我曾建议使用esm包作为Mocha内置模块支持的替代方案,但该包已不再维护,不能处理更新的语法结构如?.,并且似乎可能无法与更新的 Mocha 版本一起使用。

然而,@babel/register对此很有效:

mocha -r @babel/register -r regenerator-runtime/runtime

我正在使用这个预设(在.babelrc文件中):

{
    "presets": [
        "@babel/preset-env"
    ]
}

这个设置需要以下软件包:

  • @babel/core
  • @babel/register
  • @babel/preset-env
  • regenerator-runtime

您还可以在.mocharc.js文件中指定它们,而不是在命令行上指定:

module.exports = {
    require: [
        '@babel/register',
        'regenerator-runtime/runtime',
    ],
};

我个人到目前为止的经验是,尝试利用Mocha的新内置ESM支持仍然是一个相当大的负担,但使用这种方法非常顺畅。

之前的回答

另一种选择是使用esm包,该包不受上述限制影响:

mocha -r esm

据我个人经验,目前利用Mocha新的内置ESM支持仍然是一项相当大的负担,但使用esm软件包则非常无缝。


4
如果你想使用 mocha --watch,那么你还需要像这样并行运行测试:mocha --watch --parallel,这样 watch 不会调用 loadFiles - Joey Guerra
1
这似乎不再起作用了。这是一个简单的代码库。如果您在终端中点击+,然后输入npm test,它会失败并显示“SyntaxError: Cannot use import statement outside a module”,即使测试命令是mocha --require esm test - gman
@gman 这有点奇怪,但我和你遇到了同样的问题。也许是 Mocha 的新版本中出现了一些问题。请参见我上面更新的答案。我现在建议使用 Babel 而不是 esm这似乎仍然有效。顺便说一下,你的 import 语句中似乎有一个拼写错误,但这似乎不是你看到的错误的原因。 - JLRishe
当使用babel时,“Cannot use import statement outside a module”错误似乎又出现了,请在您的codesandbox中检查。 - matt lohkamp
1
@mattlohkamp,我在你发表评论的时间周围也遇到了同样的问题,但是我现在刚刚查看了代码沙盒,它没有出现任何问题。奇怪的是,即使没有进行任何更改,它也可以从工作状态转变为崩溃状态,然后再次工作。但是,我已经在几个实际项目中使用@babel/register进行了一段时间,并且它们一直没有出现任何问题。 - JLRishe
显示剩余3条评论

5
在我的情况下使用以下命令运行:

基本命令:

npx mocha --require esm test_path/

package.json

"scripts": {
    // ...
    "test": "npx mocha --require esm --reporter spec test_path/"
}

运行中

npm test

4
我遇到了 Cannot find module 'esm' 的错误。 - mkrasowski
大概是指这个。对于不了解--require如何工作的人来说并不是非常清楚。 - c24w

-1
关于你的主要问题:
“是否可以在 Mocha 测试中使用 ES6 模块?”
是的,从Mocha版本9开始:
Mocha 先采用ESM!这意味着它现在将使用ESM import(test_file)加载测试文件,而不是CommonJS require(test_file)。这不是问题,因为import也可以加载大多数require加载的文件。在这种情况下很少失败,它会回退到require(...)。这种ESM-first方法是Mocha ESM迁移的下一步,并允许ESM加载器加载和转换测试文件。
您还需要使用支持import的 Node 版本, 这将是>= 13.2.0
关于“Unexpected token import”问题 - 这里的其他人写了很好的答案,但这里有另一个相关问题的更好答案:

如何让mocha/babel实时转译我的测试代码?


-1

27
请在终端中运行 npm i -D esm 命令来安装 ESM 模块,然后使用 mocha --require esm 命令运行测试。 - arve0
7
似乎这并不是一个答案,因为Node已经支持了这项功能,所以问题在于如何让Mocha在Node中启用此功能。 - user239558
3
@user239558 那并不是那么容易。除非 Mocha 决定支持,否则无法使用内置的支持。你可以通过传递标志来启用 Node 中的模块支持,例如:node --experimental-modules $(npm bin)/_mocha,但如果运行 import * from './my-module' 的代码,它仍然会崩溃。原因是 Mocha 使用普通的 CommonJS require 导入测试文件,而 Node 要求使用 import 来启用以 ES 模块形式运行文件的模式。这意味着 Mocha 必须改变才能使其起作用。在此之前,ESM 或转译是您的答案。 - oligofren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接