Tri state, split brain, order dependency
Just few days ago I wrote an article about rewiremock, and in the conclusion I pointed a little problem:
You have a ModuleA, which requires ModuleB and ModuleC. And ModuleC will also require ModuleB.
Next you mock ModuleB with your own one.
Question: Who is the killer?
PS: And you dont know which module is required first — C or B.

So lets check out those suspects, who still alive:
- Proxyquire, in case ModuleC required first will NOT mock B. In case ModuleB is required first — will mock ALL occurrences. Because proxyquire first wipes cache, next setups its own
extensionhandler, mocks only first level of dependencies, and worksaftercache. So, if ModuleC will be loaded first, anunmockedModuleB will be saved into the cache, and next used again. - Rewire, or any other babel/loader based variant will
rewriteModuleA to usesomething elseas ModuleB. ModuleC`s behaviour will be untouched. - Jest, Mockery or quibble will always mock(and wipe) EVERYTHING.
Why they are so different?
Rewire actually hack source module, rewiring and rewriting it. But nothing more. So you always can predict how it will work. No surprises. But sometimes you have to mock something deeper. And you cant.
Thus can cause split brain — half of code use one version of a module, and second half — another.
Proxyquire uses nodejs`s extension-handles. The lowest possible layer. It just loads a bit different version of a module. And then stores it into the cache. And load will be fired only if it cache was clean before. So proxyquire technically can only mock everything that is not in the cache. Absolutely random behavior. And behold an Order Dependency.
JFYI: Proxyquire will also keep
mockedversion of files in nodejs`s cache. This can, and actually will break rest of your`s tests. Use noPreserveCache.
Mockery uses nodejs`s Module._load — almost the highter possible layer. It works before cache, and did not store anything to it. But you have to load source module in any case — you have to call to original _load, and that one will use cache.
Anyway, mocking everything is a devil. Don’t mock what you don’t own.
Jest provides most “powerfull“ mocks — you can specify default mocks for a module via __mock__ directory, auto-generate mock for a module and overload any module at any place. Yet again they use Module._load but — you actually unable to turn of that magic (at all, you can disable it for a single module).
And, a bit strange, there is no examples why to mock, how to mock, when to mock. Nothing!
So can I handle it?
So I wake up with a simple questing — can rewiremock handle everything of this?
BTW: rewiremock uses Module._load like a mockery, but in more smart way.
There is just a 4 tests to pass:
moduleA=moduleB+moduleCmoduleA=moduleC+moduleB
And next 2 behaviors — when moduleC will contain mockedB and when will not.
So, just a simple situation when you actually can control and create your own behavior.
So, for a first — I`v got an order independency for all tests. Good start.
For a second — I can mock only first moduleB, as rewire does, or I can mock everything as mockery does.
And for the last — test run reveals that .noBeUsed is not working then relative plugin enabled.
Now everything is great, again.