Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding intersection of require calls #73

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions README.md
Expand Up @@ -133,6 +133,40 @@ myModule.__with__({
// port is still 3000 here because the promise hasn't been resolved yet
```

### Intercepting require calls
You can intercept calls to `require` by giving `rewire` a second argument.

```javascript
var rewire = require("rewire");

var myModule = rewire("../lib/myModule.js", {
'fs' : fsMock,
'./otherModule.js' : { otherFunction: function(){} }
});
```

Calls to `require` using paths found in the given object will be intercepted, and the relevant
mock object will be returned.

You can also use a function to resolve the intercepted call.


```javascript
var rewire = require("rewire");

var myModule = rewire("../lib/myModule.js", function (path){
if(/otherModule/.test(path)){
return { otherFunction: function(){} };
} else {
return undefined;
}
});
```


If the function's return value will be used as the mock object, if it is not `undefined`. Otherwise the original `require` function is called.


### Limitations

**Variables inside functions**<br>
Expand Down
11 changes: 8 additions & 3 deletions lib/index.js
Expand Up @@ -5,12 +5,17 @@ var rewireModule = require("./rewire.js");
* call myModule.__set__(name, value) and myModule.__get__(name) to manipulate private variables.
*
* @param {!String} filename Path to the module that shall be rewired. Use it exactly like require().
* @param {Object|Function} require_mocks Mock to be returned by require() within the module.
* If it is a function, then it will be called with the path of the required module as
* argument. The `this` context of the function will be the module. If the function
* returns undefined, then the old require function is used, else, then it is taken as
* the require function's return value.
* @return {*} the rewired module
*/
function rewire(filename) {
return rewireModule(module.parent, filename);
function rewire(filename, requireMocks) {
return rewireModule(module.parent, filename, requireMocks);
}

module.exports = rewire;

delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date
delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date
22 changes: 21 additions & 1 deletion lib/rewire.js
Expand Up @@ -8,7 +8,7 @@ var Module = require("module"),
/**
* Does actual rewiring the module. For further documentation @see index.js
*/
function internalRewire(parentModulePath, targetPath) {
function internalRewire(parentModulePath, targetPath, requireMocks) {
var targetModule,
prelude,
appendix,
Expand Down Expand Up @@ -36,6 +36,26 @@ function internalRewire(parentModulePath, targetPath) {
// We prepend a list of all globals declared with var so they can be overridden (without changing original globals)
prelude = getImportGlobalsSrc();

// Compute the required mocks injection code, and inject the prelude;
if(requireMocks){
if(requireMocks instanceof Function){
targetModule.__mock_require__ = requireMocks;
} else {
targetModule.__mock_require__ = function(path){
return requireMocks && requireMocks[path];
};
}

prelude += (
'var require = (function(oldRequire){' +
'return function(path){' +
'var mock = module.__mock_require__(path);' +
'return mock === undefined ? oldRequire(path) : mock;' +
'}' +
'})(require);'
);
}

// Wrap module src inside IIFE so that function declarations do not clash with global variables
// @see https://github.com/jhnns/rewire/issues/56
prelude += "(function () { ";
Expand Down
29 changes: 29 additions & 0 deletions test/testModules/sharedTestCases.js
Expand Up @@ -92,6 +92,35 @@ describe("rewire " + (typeof testEnv === "undefined"? "(node)": "(" + testEnv +
rewire("./moduleB.js").checkSomeGlobals();
});

it("should mock targeted require calls if given an object", function () {
var dummySomeOtherModule = {};
expect(rewire("./moduleA.js", {
'./someOtherModule.js' : dummySomeOtherModule
}).someOtherModule).to.equal(dummySomeOtherModule);

var dummyFs = {readFileSync:function(){}};
expect(rewire("./module.coffee", {
'fs' : dummyFs
}).__get__('fs')).to.equal(dummyFs);
});

it("should mock targeted require calls if given a function", function () {
var dummySomeOtherModule = {};
expect(rewire("./moduleA.js", function(path){
return /someOtherModule.js/.test(path) && dummySomeOtherModule;
}).someOtherModule).to.equal(dummySomeOtherModule);

var dummyFs = {readFileSync:function(){}};
expect(rewire("./module.coffee", function (path) {
return path == 'fs' && dummyFs;
}).__get__('fs')).to.equal(dummyFs);

var realFs = require('fs');
expect(rewire("./module.coffee", function (path) {
return undefined;
}).__get__('fs')).to.equal(realFs);
});

// This is just an integration test for the __set__ method
// You can find a full test for __set__ under /test/__set__.test.js
it("should provide a working __set__ method", function () {
Expand Down