34

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

Is it possible to use ES6 modules in Mocha tests? I have the problems with export and import keywords.

/* 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:

/* 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));
    });
  });
});

I launch the mocha directly through the PowerShell console. The result:

enter image description here

Andrey Bushman
  • 11,712
  • 17
  • 87
  • 182
  • 1
    https://mochajs.org/#about-babel – robertklep Sep 29 '17 at 10:55
  • http://jamesknelson.com/testing-in-es6-with-mocha-and-babel-6/ – winseybash Sep 29 '17 at 10:57
  • 3
    I think the point is that Node 8.6 supports import/export without transpilation. However, I am not sure mocha allows the `--experimental-modules` required to make use of it, so transpilation is probably still required until it does (or until the support makes it to stable) – CodingIntrigue Sep 29 '17 at 11:48
  • 4
    I think this is not duplicate question. ES modules are supported natively in top browsers and it is possible to [run Mocha tests without using Babel](https://medium.com/dailyjs/running-mocha-tests-as-native-es6-modules-in-a-browser-882373f2ecb0). – vitalets Dec 13 '17 at 18:18
  • 8
    Time has past, and it is now possible to use the import syntax with mocha, thanks to [esm](https://github.com/standard-things/esm) module. Add it to your dependencies, and just use `mocha -r esm`. You don't even need to switch to the `.mjs` extension. – Feugy May 28 '18 at 08:31
  • 3
    This question is not really a duplicate of https://stackoverflow.com/questions/46255387/unexpected-token-import-when-using-mocha-with-babel , as the latter is about Babel, and this question is not. – Flimm Jun 21 '19 at 11:30

4 Answers4

33

Mocha has support for ESM from version 7.1.0 onward (release: Feb. 26, 2020).

This requires Node 12.11.0 or higher, and is subject to the current restrictions/limitations of using modules in Node:

  • Either you must use .mjs file extensions for source files that use ES modules, or you must have "type": "module" in your package.json
  • You can't use named imports when importing from CommonJS modules
  • Local import statements have to explicitly include the .js file extension

And so on.

Updated answer

I had previously recommended using the esm package as an alternative to Mocha's built-in module support, but it is no longer being mantained, can't handle newer syntactical constructs like ?., and seems to possibly not work at all with newer versions of Mocha.

However, @babel/register seems to work well for this:

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

I'm using this with this preset (in .babelrc):

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

This setup requires the following packages:

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

You can also specify these in your .mocharc.js file instead of on the command line:

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

My personal experience as of yet is that trying to take advantage of Mocha's new, inherent ESM support is still a considerable burden, but using this approach is quite seamless.

Previous answer

Another option is to use the esm package, which is not subject to the above limitations:

mocha -r esm

My personal experience as of yet is that trying to take advantage of Mocha's new, inherent ESM support is still a considerable burden, but using the esm package is quite seamless.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 4
    If you want to use `mocha --watch` then you'll also have to run tests in parallel like `mocha --watch --parallel` so that watch doesn't call `loadFiles`. – Joey Guerra Aug 08 '20 at 18:18
  • 1
    This doesn't seem to work anymore. [Here's a simple repo](https://codesandbox.io/s/elated-sun-s0fu5). If you click `+`in the terminal and then type `npm test` it fails with "SyntaxError: Cannot use import statement outside a module" even though the test command is `mocha --require esm test` – gman Dec 27 '21 at 19:34
  • @gman That's kind of weird, but I see the same issue as you. Maybe there's something in newer versions of Mocha that break that. Please see my updated answer above. I now recommend using Babel instead of `esm`, and [that seems to still work](https://codesandbox.io/s/condescending-lederberg-xq9uv). FYI, there seems to be a typo in your `import` statement, but that doesn't seem to be the cause of the error you're seeing. – JLRishe Dec 28 '21 at 02:31
  • "Cannot use import statement outside a module" appears to be back again when using babel, check in your codesandbox – matt lohkamp Feb 11 '22 at 03:18
  • 1
    @mattlohkamp I saw the same issue as you around the time you made your comment, but I just looked at the code sandbox now and it is working without issue. Strange that it can go from working, to broken, to working without any changes being made, but I have been using @babel/register for this in several actual projects for some time now and they have been working without issue. – JLRishe Mar 03 '22 at 18:08
  • @JLRishe, any chance you could outline the "considerable burden" of using Mocha's inherent ESM support? It would help me decide whether to go the babel route as you recommend. Is it that "you must use .mjs file extensions...and so on" list of issues, or something else? – Joshua Richardson Mar 17 '22 at 05:52
  • @JoshuaRichardson The things I listed are the bulk of the "considerable burden". At least for me, I don't use .mjs extensions and I omit the file extensions from my `import` statements. So trying to use Mocha's built-in module support would probably require me to change all of my code. – JLRishe Mar 17 '22 at 10:29
  • "You can't use named imports when importing from CommonJS modules" > So what could be done in that case? – aderchox Jul 30 '22 at 17:30
5

In my case run with:

basic comand:

npx mocha --require esm test_path/

package.json

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

Runing

npm test
fitorec
  • 4,257
  • 2
  • 24
  • 18
-1

It's possible with Babel and Browserfy https://drublic.de/blog/es6-modules-using-browserify-mocha/

winseybash
  • 704
  • 2
  • 12
  • 27
Osama Bari
  • 597
  • 3
  • 15
  • 27
    `npm i -D esm` then run tests with `mocha --require esm` – arve0 Apr 21 '19 at 20:13
  • 7
    This seems like a non-answer given that node supports this out-of-the-box, so the issue is how to get mocha to enable this functionality in node. – user239558 Jun 02 '19 at 20:27
  • 3
    @user239558 It's not as easy as that. Using the built-in support isn't possible until Mocha decides it to be. You can pass the flags to enable module support in Node like this: `node --experimental-modules $(npm bin)/_mocha`, but it will still crash on running code using `import * from './my-module'`. The reason is that Mocha imports the test files using the normal CommonJS require, while Node requires it to use `import` for it to enable the mode where files are running as ES Modules. That means Mocha must change for this to work. Until that happens, ESM or transpilation is your answer. – oligofren Jun 27 '19 at 20:57
-1

Regarding your main question

Is it possible to use ES6 modules in Mocha tests?

Yes, as of Mocha version 9:

Mocha is going ESM-first! This means that it will now use ESM import(test_file) to load the test files, instead of the CommonJS require(test_file). This is not a problem, as import can also load most files that require does. In the rare cases where this fails, it will fallback to require(...). This ESM-first approach is the next step in Mocha's ESM migration, and allows ESM loaders to load and transform the test file.

You also need to use a Node version which supports import, which would be >= 13.2.0


Regarding the Unexpected token import problem - others here wrote good answers, but here's a better answer from another related question:

How does mocha / babel transpile my test code on the fly?

vsync
  • 118,978
  • 58
  • 307
  • 400