Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stub a function from a ES6 module without babel

I'm using AVA + sinon to build my unit test. Since I need ES6 modules and I don't like babel, I'm using mjs files all over my project, including the test files. I use "--experimental-modules" argument to start my project and I use "esm" package in the test. The following is my ava config and the test code.

  "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();
});

But I get the error message:

  TypeError {
    message: 'ES Modules cannot be stubbed',
  }

How can I stub an ES6 module without babel?

like image 763
Jim Jin Avatar asked Jun 08 '18 14:06

Jim Jin


1 Answers

According to John-David Dalton, the creator of the esm package, it is only possible to mutate the namespaces of *.js files - *.mjs files are locked down.

That means Sinon (and all other software) is not able to stub these modules - exactly as the error message points out. There are two ways to fix the issue here:

  1. Just rename the files' extension to .js to make the exports mutable. This is the least invasive, as the mutableNamespace option is on by default for esm. This only applies when you use the esm loader, of course.
  2. Use a dedicated module loader that proxies all the imports and replaces them with one of your liking.

The tech stack agnostic terminology for option 2 is a link seam - essentially replacing Node's default module loader. Usually one could use Quibble, ESMock, proxyquire or rewire, meaning the test above would look something like this when using 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 });

Modifying the proxyquire example to use Quibble or ESMock (both supports ESM natively) should be trivial.

like image 54
oligofren Avatar answered Nov 04 '22 02:11

oligofren