Search code examples
javascriptunit-testingimportecmascript-6stub

How to stub ES6 node_modules when using import?


I am a bit confused while writing tests. My stack is mocha, chai and sinon + babel to transpile. And recently I've started to use ES6 imports and exports. It's working great so far, but I have trouble with mocking some dependencies. Here is my case:

service.js

import {v4} from 'uuid';

function doSomethingWithUuid() {
    return v4();
}

export function doSomething() {
    const newUuid = doSomethingWithUuid();
    return newUuid;
}

service.test.js

import {doSomething} from './service';

describe('service', () => {
    it('should doSomething' () => {
        // how to test the return of doSomething ? 
        // I need to stub v4 but I don't know how...
    });
});

Things I've considered: sinon.stub, but I have not managed to make it work. Trying to import all uuid with import * as uuid from 'uuid'. But within my service.js, it's still the original function which is called... Plus as imports are supposed to be read-only, once it'll be native, this solution wouldn't work...

The only interesting thing I found on the net was this solution, to add a function in my service in order to let the outside world to override my dependencies. (see https://railsware.com/blog/2017/01/10/mocking-es6-module-import-without-dependency-injection/).

import * as originalUuid from 'uuid';

let {v4} = originalUuid;
export function mock(mockUuid) {
  ({v4} = mockUuid || originalUuid);
}

This is ok to write this little boilerplate code, but it troubles me to add it in my code... I would prefer to write boilerplate in my test or some config. Plus, I don't want to have an IoC container, I want to keep my functions as little as possible and stay as fonctional as I can...

Do you have any ideas? :)


Solution

  • You should be able to use a module like proxyquire for this. This is not tested code, but it would go something like the following:

    const proxyquire = require('proxyquire');
    const uuidStub = { };
    
    const service = proxyquire('./service', { uuid: uuidStub });
    uuidStub.v4 = () => 'a4ead786-95a2-11e7-843f-28cfe94b0175';
    
    describe('service', () => {
      it('should doSomething' () => {
        // doSomething() should now return the hard-coded UUID
        // for predictable testing.
      });
    });