Require-Again (and again and again and again)

There are some parts of the Habitica that have different behaviors when running the app in production and running the app locally in development. For instance, development mode:

  • has debug routes to make QA testing easier
  • does not send transactional emails (Log-in reminders, flag message, etc)
  • does not send analytics information

However, testing these behaviors can be difficult because Node's module system caches the files whenever you require them. So if I have a file like this:

// my-module.js
import nconf from 'nconf';

const IS_PROD = nconf.get('IS_PROD');

if (IS_PROD) {  
  module.exports = realFunction; // does something
} else {
  module.exports = noopFunction; // does nothing
}

When testing, I can't check production versus development behavior, because Node will cache the module in the state it was when it was first required.

In fact, if another test file requires a lib that uses this module, we'll get the file in the state it was during those tests.

For this reason, I wrote require-again. A module that returns a freshly required version of the module.

Here's an example of how you could use it:

import sinon from 'sinon';  
import nconf from 'nconf';

describe('myModule', () => {  
  context('production', () => {
    before(() => {
      sinon.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
    });

    after(() => {
      nconf.get.restore();
    });

    it('does something', () => {
      let myModule = requireAgain('./path/to/my-module');

      let result = myModule();

      // assert on result
    });
  });

  context('development', () => {
    before(() => {
      sinon.stub(nconf, 'get').withArgs('IS_PROD').returns(false);
    });

    after(() => {
      nconf.get.restore();
    });

    it('noops', () => {
      let myModule = requireAgain('./path/to/my-module');

      // assert that it noops
    });
  });
});

How do you deal with this challenge? Let us know in the JavaScript guild.