jhnns / rewire

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

Possible to rewire anonymous function #176

Closed JasonSome closed 4 years ago

JasonSome commented 4 years ago

Is it possible to rewire an anonymous function that is returned as module.exports? For example, if I want to have a dep.js file with the following content:

module.exports = function(inp) { blah }

How can I rewire it to change the module.exports (__set__ it) to another function? (it is useful to me, because I am about to stub it for testing another code file that require-s it, but anyway don't care about why that would be useful to me)

rensbaardman commented 4 years ago

In this case, you don't really have to inject anything – you can just simply mock this function, right? (without using rewire) If you need more it would be helpful if you can include an example.

JasonSome commented 4 years ago

@rensbaardman why is that? The specific use case is as follows: the file usingDep.js does something like this:

module.exports = function(input2) { const depFuncs = require('./dep')(input2); blah_blah_uses_dep }

and I want to unit test this usingDep.js so I need to stub out the default exported function (module.exports) of dep.js.

So, testing it with rewire would be a breeze, if I could. Please note that I don't want to install extra packages, such as proxyquire.

rensbaardman commented 4 years ago

Ah, in that case: no, that isn't possible. See the section on limitations in the README:

Variables inside functions can not be changed by rewire. This is constrained by the language.

But, could moving the const depFuncs = require('./dep') out of the function be an option? Then you could do something like:

// dep.js
module.exports = function(something) {
    return something
}
// usingDep.js
const dep = require('./dep.js')

module.exports = function(input) {
    const result = dep(input)
    console.log(result)
}
// usingDep.test.js
const rewire = require('rewire')
const usingDep = rewire('./usingDep.js')

const mockFunction = function(something) { return something + something }

usingDep.__set__('dep', mockFunction)
usingDep('test')

Then testing this by running node usingDep.test.js gives testtest on the output, showing that dep.js was succesfully faked/mocked.

JasonSome commented 4 years ago

Well, that is certainly a good idea, but I am not sure I agree with your saying:

Ah, in that case: no, that isn't possible.

Just to note, the reason I consider that here is that I don't want to rewire the depFuncs variable. I want to modify the require-d module (as is usually done to stub out whole modules: you also require them from testing code and then stub out the wanted function, so require.cache gets modified on-the-fly).

rensbaardman commented 4 years ago

Sorry, I miss what you are trying to do. If you could include a minimal example of what doesn't work, I could take a look. Or maybe it's just over my head 😉

JasonSome commented 4 years ago

Anyway, thanks for your kind help. I found one way to correct my issue: get all those to-be-mocked requires outside of the function in files using it, so now I can rewire them anyways without rewiring the original module.exports default function.