javascriptunit-testinges6-classproxyquire

Proxyquire not stubbing my required class


I have a class AProvider that requires './b.provider'.

const BProvider = require('./b.provider');

class AProvider {
  static get defaultPath() {
    return `defaults/a/${BProvider.getThing()}`;
  }
}

module.exports = AProvider;

b.provider.js is adjacent to a.provider.js and looks like

global.stuff.whatever = require('../models').get('Whatever'); // I didn't write this!

class BProvider {
  static getThing() {
    return 'some-computed-thing';
  }
}
module.exports = BProvider;

In my test I use proxyquire to mock out ./b.provider as follows:

import { expect } from 'chai';
import proxyquire from 'proxyquire';

describe('A Provider', () => {
  const Provider = proxyquire('../src/a.provider', {
    './b.provider': {
      getThing: () => 'b-thing'
    },
  });

  describe('defaultPath', () => {
    it('has the expected value', () => {
      expect(Provider.defaultPath).to.equal('defaults/a/b-thing')
    });
  });
});

However when I run the test BProvider is still requiring the actual './b.provider' not the stub and BProvider's reference to global.stuff.whatever is throwing an error.

Why isn't this working?


Solution

  • The answer as to why this is happening is as follows

    proxyquire still requires the underlying code before stubbing it out. It does this to enable callthroughs.

    The solution is simply to explicitly disallow callthroughs.

    The test becomes:

    import { expect } from 'chai';
    import proxyquire from 'proxyquire';
    
    describe('A Provider', () => {
      const Provider = proxyquire('../src/a.provider', {
        './b.provider': {
          getThing: () => 'b-thing',
          '@noCallThru': true
        },
      });
    
      describe('defaultPath', () => {
        it('has the expected value', () => {
          expect(Provider.defaultPath).to.equal('defaults/a/b-thing')
        });
      });
    });
    

    Running this test works perfectly.