3

Since importing an ES6 module gives you a read-only view on that module, mocking it produces the error 'x' is read-only. This is preventing me from isolating the code under test by breaking its dependencies. I'm not sure how to get around this.

http://exploringjs.com/es6/ch_modules.html

*I would have thrown up a Plunker but I couldn't get it to recognize the import statement, and JSFiddle doesn't seem to allow other files, which would have been for the exported modules.

nullsteph
  • 791
  • 15
  • 28

2 Answers2

2

If you're using sinon, my advice is to stop using it. They don't support mocking readonly modules and got pretty aggressive about the topic https://github.com/sinonjs/sinon/issues/1711

With jest, in the other hand, you can easily mock an ES6 read-only module like this:

const myMockedModule = {
   ...jest.requireActual('my-es6-readonly-module'),
   theFunctionIWantToMock: jest.fn(),
}
jest.mock('my-es6-readonly-module', () => myMockedModule);

You need to put it as the first line of your spec. With that approach, you can mock any direct exported item from any module, even if it is read-only, as jest intercepts the require method. This is also not very practicable with mocha because mocha loads all tests in the same process and some other test suite may load, directly or indirectly, the module you want to mock, and it'll screw your test. Jest is the way to go, as it loads every single spec in a separated process, making one spec doesn't interfere with another, so this mocking approach become viable.

-1

My solution was to change my how I export. If I export an object of properties, instead of the individual properties themselves, I don't get the error. This seems to be because Object.freeze is only one level deep, so the exported object is frozen, but not is children.

import {ua} from './index';

./index.js exports a named object, with the props I want to override:

export const ua = {
    deleteUser,
    loadUsers
};

This allowed the following in my test code:

ua.loadUsers = function () {
           expect(delUspy.calledOnce).toBe(true);
           expect(loadUspy.callCount).toEqual(1);
           done();
        };

...but ua = {} failed because its been frozen.

The answer then is to export objects of props, and avoid importing individual properties.

nullsteph
  • 791
  • 15
  • 28