jhnns / rewire

Easy monkey-patching for node.js unit tests
MIT License
3.08k stars 127 forks source link

Support intercepting of require() #68

Open sidhuko opened 9 years ago

sidhuko commented 9 years ago

I've been trying to use rewire with FRP languages such as ramda and experienced an issue/downfall which I'd like to bring up for discussion. This relates to previous tickets which have mentioned having a way of overriding dependencies on initial rewire call. As the isInList caches the function creation with one argument to optimise the call and improve code readability it is excluded in the __set__ update therefore returning the wrong result until the function is moved into the executed code block (see hacked example).

It is a very primitive example but when working on nested promise chains where you have nested levels it becomes cumbersome to test and fix.

Suggested fix would be to allow certain modules to be changed on initialisation;

var example = rewire(example, {__set__: {'map', {'orders', 'test_order'}}}); 

This would stop your users needing to use other third party modules such as mockery or quire to change required modules on instantiation.

Example file:

var R = require('ramda');
var map = require('./map'); // example { 'orders': 'an_order' }

var isInList = R.partialRight(R.prop, map);

module.exports = function (item) {
  return isInList(item) // item of order would return 'an_order'
};

Example test:


var sinon = require('sinon');
var rewire = require('rewire');
var expect = require('chai').expect;
var example = rewire('./example');

describe('client', function () {  
  var map = {
    'orders': 'test_order'
  };

  before(function () {
    client.__set__('map', map);
  });

  it('should be a function', function () {
    expect(client('item')).to.equal('test_order'); // fails and returns 'an_order'
  });
});

Hacked example file to work:

var R = require('ramda');
var map = require('./map'); // example { 'orders': 'an_order' }

module.exports = function (item) {

  var isInList = R.partialRight(R.prop, map);

  return isInList(item) // when run the test would now pass with 'test_order'
};
jhnns commented 9 years ago

I understand the need to intercept require() calls, but I am currently not planning to implement it, because then it needs to be implemented for rewire-webpack and for browserify someday too. Otherwise I will get new issues opened saying "feature xyz is not working".

You could wrap you code in an init() function which you can call again to re-initialize the cached functions.

sfescape commented 9 years ago

This is unfortunate, I'm feeling compelled to use jest exactly for this feature. I'm glad to see from #73 that you're revisiting this decision.

thlorenz commented 8 years ago

For intercepting require you may want to have a look at proxyquire which does exactly (and only) that. For all other overrides you can then still use rewire.

Jest would work as well afaik but is a much larger package.

YakovL commented 2 years ago

@thlorenz do know you if it's possible to combine proxyquire and rewire? Meaning to load a module with injection and get private variables from it?

thlorenz commented 2 years ago

I have not used rewire and thus would not know, sorry.