Andrey Bushman
Andrey Bushman

Reputation: 12506

Is it possible to use ES6 modules in Mocha tests?

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

Upvotes: 36

Views: 36677

Answers (4)

JLRishe
JLRishe

Reputation: 101680

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.

I had previously recommended using the esm package as an alternative to Mocha's built-in module support, but it is no longer being maintained, 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.

Upvotes: 36

vsync
vsync

Reputation: 130195

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?

Upvotes: -1

fitorec
fitorec

Reputation: 4765

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

Upvotes: 5

Osama Bari
Osama Bari

Reputation: 598

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

Upvotes: -1

Related Questions