node.jsunit-testingsinonproxyquirerewire

How to force a return value from a mocked non-exported function using sinon or proxyquire or rewire?


I am just getting started unit testing nodejs. I have been using mocha, chai and sinon.

I hit a snag when I wanted to test a function which is not exported. proxyquire looks good, as does rewire.

There are lots of tutorials, but they tend to be simplistic. E.g

// Software under test
function saySecret() {      // this function is *not* exported
  return '🤫';
}

// Unit test file
import utilsRewire from './utils.js';

describe('saySecret', () => {
  it('returns shh emoji', () => {
    const saySecret = utilsRewire.__get__('saySecret'); // 👈 the secret sauce

    expect(saySecret()).toBe('🤫');
  });
});

While that is nice, I want to be able to force the function saySecret to return a specific value. The reason being that the function is called by a function which is exported, and I want to unit test the outer function, forcing it down failure paths.

How can I do that with sinon/proxyquire/rewire?


Solution

  • The API rewiredModule.set(name: String, value: *): Function of rewire package can do this.

    E.g.

    index.ts:

    function saySecret() {
      return '🤫';
    }
    
    export function outer() {
      return saySecret();
    }
    

    index.test.ts:

    import rewire from 'rewire';
    import sinon from 'sinon';
    
    describe('71285081', () => {
      it('should pass', () => {
        const mod = rewire('./');
        const saySecretStub = sinon.stub().returns('Ok');
        mod.__set__('saySecret', saySecretStub);
        const actual = mod.outer();
        sinon.assert.match(actual, 'Ok');
        sinon.assert.calledOnce(saySecretStub);
      });
    });
    

    Test result:

    mocha --require ts-node/register --require jsdom-global/register --timeout 5000 "index.test.ts"
    
    
    
      71285081
        ✓ should pass (86ms)
    
    
      1 passing (90ms)