joelgriffith.net
  • About
  • GitHub
  • Twitter
  • LinkedIn
  • Resume

You should use Rewire

May 26, 2015

One of the coolest, almost unheard of libraries, I’ve ever had the joy of working with is rewire. If you haven’t already heard of it, rewire allows you to rewire variables in a JavaScript file to another reference.

Wut.

Yeah, you heard me, you can do some crazy dependency-injection on the galactic level with this stuff:

mylib.mspec.js

var rewire = require('rewire');
var mylib = rewire('mylib');

// Let's pretend that `mylib` loads something we want to test an integration with
mylib.__set__('otherlib', sinon.spy());

This example rewires the variable defenition of otherlib in mylib to a sinon spy. That way we can test that mylib is interacting appropriately with otherlib, and we can assert behaviours on it.

Later, we can do stuff like:

it('should call the other lib', function() {
  mylib.callOtherLib();
  expect(mylib.__get__('otherlib').called).to.be.true;
});

Since we never assigned our spy to a variable in our test file, we can call the special rewire __get__ method to retrieve that reference in the current context.

So, we know we can get and set variables in a file we don’t have exposure to, what are the limits? Well, you can only touch references at the “root” level of the file. Here’s an example:

mylib.js

var otherLib = require('otherLib');

module.exports = function(bar) {
  var cantBeRewired = 'baz';

  return cantBeRewired + bar;
}

In this example, we cannot touch the cantBeRewired variable since it’s not in the “root” level of the file. To do so, we’d have to pull that refernce out of the foo function:

var otherLib = require('otherLib');
var canBeRewired = 'baz';

module.exports = function(bar) {
  return canBeRewired + bar;
}

Since the reference is now in the “root” scope of this module, we can rewire it in our tests to whatever we want.

myLib.mspec.js

var rewire = require('rewire');
var myLib = rewire('myLib');

// Set it `canBeRewired` to something else
myLib.__set__('canBeRewired', 'dir');

myLib('ectory'); // Should print `directory`

So, there you have it. Use rewire and limit your testing area to only the code you wish to test.