Socket
Socket
Sign inDemoInstall

rewire

Package Overview
Dependencies
Maintainers
1
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rewire - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

lib/__get__.js

4

lib/index.js

@@ -16,3 +16,3 @@ "use strict"; // run code in ES5 strict mode

*/
function rewire(request, mocks, injections, leaks, cache) {
function rewire(request, cache) {
delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date

@@ -24,3 +24,3 @@

return rewireModule(module.parent, request, mocks, injections, leaks, cache);
return rewireModule(module.parent, request, cache);
}

@@ -27,0 +27,0 @@

"use strict"; // run code in ES5 strict mode
var Module = require("module"),
nodeWrapper0 = Module.wrapper[0], // caching original wrapper
nodeWrapper1 = Module.wrapper[1],
getLeakingSrc = require("./getLeakingSrc.js"),
getInjectionSrc = require("./getInjectionSrc.js"),
rewiredModules = [];
__get__ = require("./__get__.js"),
__set__ = require("./__set__.js"),
getImportGlobalsSrc = require("./getImportGlobalsSrc.js"),
moduleWrapper0 = Module.wrapper[0], // caching original wrapper
moduleWrapper1 = Module.wrapper[1], // caching original wrapper
rewiredModules = []; // cache for all rewired modules so it can be reset anytime
function restoreOriginalWrappers() {
Module.wrapper[1] = nodeWrapper1;
Module.wrapper[0] = moduleWrapper0;
Module.wrapper[1] = moduleWrapper1;
}

@@ -17,15 +20,18 @@

*/
function rewire(parentModule, filename, mocks, injections, leaks, cache) {
function rewire(parentModule, filename, cache) {
var testModule,
nodeRequire,
wrapperExtensions = "";
prepend,
append;
function requireMock(path) {
/**
* Proxies the first require call in order to draw back all changes.
* Thus our changes don't influence other modules
*
* @param {!String} path
*/
function requireProxy(path) {
restoreOriginalWrappers(); // we need to restore the wrappers now so we don't influence other modules
if (mocks && mocks.hasOwnProperty(path)) {
return mocks[path];
} else {
return nodeRequire.call(testModule, path); // node's require only works when "this" points to the module
}
testModule.require = nodeRequire; // restoring original nodeRequire
return nodeRequire.call(testModule, path); // node's require only works when "this" points to the module
}

@@ -38,4 +44,4 @@

// Init vars
filename = Module._resolveFilename(filename, parentModule); // resolve full filename relative to the parent module
// Resolve full filename relative to the parent module
filename = Module._resolveFilename(filename, parentModule);

@@ -48,29 +54,33 @@ // Special support for older node versions that returned an array on Module._resolveFilename

// Create testModule as it would be created by require()
testModule = new Module(filename, parentModule);
nodeRequire = testModule.require; // caching original node require
// Prepare module for injection
if (typeof injections === "object") {
wrapperExtensions += getInjectionSrc(injections);
} else if (typeof injections === "string") {
wrapperExtensions += injections;
}
// Patching requireProxy
nodeRequire = testModule.require;
testModule.require = requireProxy;
// Prepare module for leaking private vars
if (Array.isArray(leaks)) {
wrapperExtensions += getLeakingSrc(leaks);
}
Module.wrapper[1] = wrapperExtensions + nodeWrapper1;
// We prepend a list of all globals declared with var so they can be overridden (without changing original globals)
prepend = getImportGlobalsSrc();
// Mocking module.require-function
testModule.require = requireMock;
// Loading module
// We append our special setter and getter.
append = "module.exports.__set__ = " + __set__.toString() + "; ";
append += "module.exports.__get__ = " + __get__.toString() + "; ";
// Apply prepend and append
Module.wrapper[0] = moduleWrapper0 + prepend;
Module.wrapper[1] = append + moduleWrapper1;
//console.log(Module.wrapper);
// Let the show begin
testModule.load(testModule.id);
// Store the rewired module in the cache when enabled
if (cache) {
rewiredModules.push(filename); // save in private cache for .reset()
require.cache[filename] = testModule;
rewiredModules.push(filename); // save in private cache for .reset()
}
restoreOriginalWrappers(); // this is only necessary if nothing has been required within the module
// This is only necessary if nothing has been required within the module
restoreOriginalWrappers();

@@ -80,2 +90,5 @@ return testModule.exports;

/**
* Deletes all rewired modules from the cache
*/
rewire.reset = function () {

@@ -82,0 +95,0 @@ var i;

{
"name" : "rewire",
"version" : "0.1.3",
"version" : "0.2.0",
"description" : "Dependency injection for node.js applications",

@@ -10,3 +10,5 @@ "keywords" : [

"unit",
"test"
"test",
"leak",
"inspect"
],

@@ -31,5 +33,2 @@ "author" : {

},
"dependencies": {
"toSrc": "0.1.x"
},
"devDependencies": {

@@ -36,0 +35,0 @@ "mocha": "1.1.x",

@@ -5,8 +5,8 @@ rewire

rewire allows you to modify the behaviour of modules for better unit testing. You may
rewire adds a special setter and getter that allow you to modify the behaviour of modules
for better unit testing. You may
- provide mocks for other modules
- introduce mocks for other modules
- leak private variables
- override variables within the module
- inject your own scripts
- override variables within the module.

@@ -25,7 +25,5 @@ rewire does **not** load the file and eval the contents to emulate node's require mechanism. In fact it uses node's own require to load the module. Thus your module behaves exactly the same in your test environment as under regular circumstances (except your modifications).

### For older node versions
**For older node versions:**<br />
rewire is tested with node 0.6.x. I recommend to run the unit tests via `mocha` in the rewire-folder before using rewire with older node versions.
rewire is tested with node 0.6.x. I recommend to run the unit tests via `mocha` in the rewire-folder before
using rewire with older node versions.
-----------------------------------------------------------------

@@ -38,79 +36,75 @@ <br />

```javascript
var rewire = require("rewire"),
rewiredModule;
var rewire = require("rewire");
// Default
////////////////////////////////
// rewire acts exactly like require when omitting all other params
rewire("./myModuleA.js") === require("./myModuleA.js"); // = true
// rewire acts exactly like require.
var myRewiredModule = rewire("../lib/myModule.js");
myRewiredModule === require("../lib/myModule.js"); // = true
// Mocks
////////////////////////////////
var mockedModuleB = {},
mockedFs = {},
mocks = {
"fs": mockedFs,
"path/to/moduleB.js": mockedModuleB
};
// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123
// The rewired module will now use your mocks instead of fs
// and moduleB.js. Just make sure that the path is exactly as
// in myModuleA.js required.
rewiredModule = rewire("./myModuleA.js", mocks);
// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
readFile: function (path, encoding, cb) {
cb(null, "Success!");
}
});
myModule.readSomethingFromFileSystem(function (err, data) {
console.log(data); // = Success!
});
// Injections
////////////////////////////////
var injections = {
console: {
log: function () { /* be quiet */ }
},
process: { argv: ["someArgs"] },
__filename: "some/other/dir"
};
// All later requires will now return the module with the mock.
myModule === require("./myModule.js"); // = true
// This will inject
// var console = {log: function () { /* be quiet */ }};
// var process = {argv: ["someArgs"] };
// var __filename = "some/other/dir";
// at the bottom of the module.
// This way you can override private variables within the module
rewiredModule = rewire("./myModuleA.js", null, injections);
// You can also pass a script to inject
rewiredModule =
rewire("./myModuleA.js", null, "console.log('hellooo');"); // prints "hellooo"
// You can set different variables with one call.
myModule.__set__({
fs: fsMock,
http: httpMock,
someOtherVar: "hello"
});
// You may also override globals. These changes are only within the module,
// so you don't have to be afraid that other modules are influenced by your mock.
myModule.__set__({
console: {
log: function () { /* be quiet */ }
},
process: {
argv: ["testArg1", "testArg2"]
}
});
// Leaks
////////////////////////////////
var leaks = ["myPrivateVar1", "myPrivateVar2"];
// This will inject
// module.exports._ = {myPrivateVar1: myPrivateVar1, myPrivateVar2: myPrivateVar2}
// at the bottom of the module.
rewiredModule = rewire("./myModuleA.js", null, null, leaks);
// But be careful, if you do something like this you'll change your global
// console instance.
myModule.__set__("console.log", function () { /* be quiet */ });
// You now can access your private varialbes under the special __-object
rewiredModule.__.myPrivateVar1; // returns former private variable myPrivateVar1
rewiredModule.__.myPrivateVar2; // returns former private variable myPrivateVar2
// By getting private variables you can test for instance if your
// module is in a specific state
assert.ok(myModule.__get__("currentState") === "idle");
// Cache
////////////////////////////////
// By disabling the module cache the rewired module will not be cached.
// Any require()-calls will now return the original module again instead
// of the rewired. Caching is enabled by default.
rewire("./myModuleA.js", null, null, null, false) !==
require("./myModuleA.js"); // = true
// You can also disable caching when loading the rewired module. All
// subsequent calls of require() will than return the original module again.
rewire("./myModule.js", false) === require("./myModule.js"); // = false
// This removes all rewired modules from require.cache.
// Every call of rewire returns a new instance and overwrites the old
// one in the module cache.
rewire("./myModule.js") === rewire("./myModule.js"); // = false
// If you want to remove all your rewired modules from the
// cache just call rewire.reset().
// Do this before every unit test to ensure a clean testing environment.
rewire.reset();
// IMPORTANT: You should call this before every unit test to ensure
// a clean test environment.
```

@@ -123,3 +117,3 @@

**rewire(***filename, mocks, injections, leaks, cache***)**
**rewire(***filename, cache***): {RewiredModule}**

@@ -129,11 +123,2 @@ - *{!String} filename*: <br/>

- *{Object} mocks (optional)*: <br/>
An object with mocks.
- *{Object|String} injections (optional)*: <br />
If you pass an object, all keys of the object will be `var`s within the module. You can also eval a string.
- *{Array&lt;String&gt;} leaks (optional)*: <br/>
An array with variable names that should be exported. These variables are accessible via `myModule.__`.
- *{Boolean=true} cache (optional)*: <br />

@@ -143,4 +128,2 @@ Indicates whether the rewired module should be cached by node so subsequent calls of `require()` will

Returns the rewired module.
**rewire.reset()**

@@ -150,49 +133,21 @@

-----------------------------------------------------------------
<br />
**RewiredModule.&#95;&#95;set&#95;&#95;(***name, value***)**
## Please note
### mocks
Keys should be exactly the same like they're required in the target module.
So if you write `require("../../myModules/myModuleA.js")` you need to pass
`{"../../myModules/myModuleA.js": myModuleAMock}`.
- *{!String} name*: <br/>
Name of the variable to set. The variable should be a global or defined with `var` in the top-level
scope of the module.
### injections
All scripts are injected at the end of the module. So if there is any code in your module
that is executed during `require()`, your injected variables will be undefined at this point.
- *{&lowast;} value*: <br/>
The value to set
Imagine `rewire("./myModule.js", null, {console: null});`:
**RewiredModule.&#95;&#95;set&#95;&#95;(***env***)**
```javascript
console.log("Hello"); // ouch, that won't work. console is undefined at this point because of hoisting
- *{!Object} env*: <br/>
Takes all keys as variable names and sets the values respectively.
// End of module ///////////////
// rewire will inject here
var console = null;
```
**RewiredModule.&#95;&#95;get&#95;&#95;(***name***): {&lowast;}**
### leaks
Leaks are executed at the end of the module. If a `var` is undefined at this point you
won't be able to access the leak (because `undefined`-values are [copied by value](http://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language)).
A good approach to this is:
Returns the private variable.
```javascript
var myLeaks = {};
module.exports = function (someValue) {
myLeaks.someValue = someValue;
};
// End of module ///////////////
// rewire will inject here
module.exports.__ = {myLeaks: myLeaks};
```
Because ```myLeaks``` is defined at the end of the module, you're able to access the leak object and all leaks that
are attached to it later during runtime. Because myLeaks is not exposed under regular circumstances your
module interface stays clean.
### reset
You should call this before every unit test to ensure a clean test environment.
-----------------------------------------------------------------

@@ -199,0 +154,0 @@ <br />

@@ -7,6 +7,8 @@ "use strict"; // run code in ES5 strict mode

// check if debugging works with rewire.
var debuggerModule = rewire("./testModules/debuggerModule.js", null, {
someVar: "Look if you can see me in your IDE when holding at the breakpoints"
});
var debuggerModule = rewire("./testModules/debuggerModule.js");
debugger;
debuggerModule.__set__("myNumber", 1);
debuggerModule();

@@ -7,14 +7,18 @@ "use strict"; // run code in ES5 strict mode

var testModules = [
path.resolve(__dirname, "./testModules/index.js"),
path.resolve(__dirname, "./testModules/A/moduleA.js"),
path.resolve(__dirname, "./testModules/B/moduleB.js"),
path.resolve(__dirname, "./testModules/C/moduleC.js")
];
var testModules = {
A: path.resolve(__dirname, "./testModules/moduleA.js"),
B: path.resolve(__dirname, "./testModules/moduleB.js"),
someOtherModule: path.resolve(__dirname, "./testModules/someOtherModule.js"),
emptyModule: path.resolve(__dirname, "./testModules/emptyModule.js")
};
function cleanRequireCache() {
var i;
var moduleName,
modulePath;
for (i = 0; i < testModules.length; i++) {
delete require.cache[testModules[i]];
for (moduleName in testModules) {
if (testModules.hasOwnProperty(moduleName)) {
modulePath = testModules[moduleName];
delete require.cache[modulePath];
}
}

@@ -25,74 +29,93 @@ }

beforeEach(cleanRequireCache); // ensuring a clean test environment
it("should work like require() when omitting all other params", function () {
expect(rewire("./testModules/A/moduleA.js")).to.be(require("./testModules/A/moduleA.js"));
it("should work like require()", function () {
expect(rewire("./testModules/moduleA.js")).to.be(require("./testModules/moduleA.js"));
cleanRequireCache();
expect(rewire("../test/testModules/moduleA.js")).to.be(require("../test/testModules/moduleA.js"));
cleanRequireCache();
expect(rewire(testModules.A)).to.be(require(testModules.A));
});
it("should require all mocks", function () {
var rewired,
fsMock = {},
mocks = {},
moduleBMock = {},
moduleCMock = {},
toSrcMock = {},
indexMock = {};
it("should modify the module so it provides a __set__ - function", function () {
expect(rewire(testModules.A).__set__).to.be.a(Function);
expect(rewire(testModules.B).__set__).to.be.a(Function);
});
it("should modify the module so it provides a __get__ - function", function () {
expect(rewire(testModules.A).__get__).to.be.a(Function);
expect(rewire(testModules.B).__get__).to.be.a(Function);
});
it("should not influence other modules", function () {
var rewiredModuleA = rewire(testModules.A);
mocks["fs"] = fsMock;
mocks[path.resolve(__dirname, "./testModules/B/moduleB.js")] = moduleBMock;
mocks["../C/moduleC.js"] = moduleCMock;
mocks["toSrc"] = toSrcMock;
mocks["../"] = indexMock;
rewired = rewire("./testModules/A/moduleA.js", mocks);
expect(rewired.fs).to.be(fsMock);
expect(rewired.b).to.be(moduleBMock);
expect(rewired.c).to.be(moduleCMock);
expect(rewired.toSrc).to.be(toSrcMock);
expect(rewired.index).to.be(indexMock);
expect(require(testModules.someOtherModule).__set__).to.be(undefined);
expect(require(testModules.someOtherModule).__get__).to.be(undefined);
expect(require("fs").__set__).to.be(undefined);
expect(require("fs").__get__).to.be(undefined);
});
it("should inject object modifications", function () {
var rewired,
injections = {
process: {
argv: ["arg1", "arg2", "arg3"]
},
console: 123
};
it("should not influence global objects by default", function () {
expect(function () {
rewire(testModules.A).checkSomeGlobals();
rewire(testModules.B).checkSomeGlobals();
}).to.not.throwException();
});
it("should provide the ability to set private vars", function () {
var rewiredModuleA = rewire(testModules.A),
newObj = {};
rewired = rewire("./testModules/A/moduleA.js", null, injections);
rewired.exportAll();
expect(rewired.process).not.to.be(process);
expect(process.argv).not.to.eql(injections.process.argv);
expect(rewired.process).to.eql(injections.process);
expect(rewired.console).to.be(123);
expect(rewiredModuleA.getMyNumber()).to.be(0);
rewiredModuleA.__set__("myNumber", 2);
expect(rewiredModuleA.getMyNumber()).to.be(2);
rewiredModuleA.__set__("myObj", newObj);
expect(rewiredModuleA.getMyObj()).to.be(newObj);
});
it("should inject custom scripts", function () {
var rewired,
script = "var console = 456;";
it("should provide the ability to get private vars", function () {
var rewiredModuleA = rewire(testModules.A);
rewired = rewire("./testModules/A/moduleA.js", null, script);
rewired.exportAll();
expect(rewired.console).to.be(456);
expect(rewiredModuleA.__get__("myNumber")).to.be(rewiredModuleA.getMyNumber());
expect(rewiredModuleA.__get__("myObj")).to.be(rewiredModuleA.getMyObj());
});
it("should leak private variables with both exports-styles (exports.bla = bla and module.exports = bla)", function () {
var rewired,
leaks = ["myPrivateVar"];
it("should provide the ability to inject mocks", function (done) {
var rewiredModuleA = rewire(testModules.A),
mockedFs = {
readFileSync: function (file) {
expect(file).to.be("bla.txt");
done();
}
};
rewired = rewire("./testModules/privateModules/privateModuleA.js", null, null, leaks);
expect(rewired.__.myPrivateVar).to.be("Hello I'm very private");
rewired = rewire("./testModules/privateModules/privateModuleB.js", null, null, leaks);
expect(rewired.__.myPrivateVar).to.be("Hello I'm very private");
rewiredModuleA.__set__("fs", mockedFs);
rewiredModuleA.readFileSync();
});
it("should leak private functions with both exports-styles (exports.bla = bla and module.exports = bla)", function () {
var rewired,
leaks = ["myPrivateFunction"];
it("should not influence other modules when injecting mocks", function () {
var rewiredModuleA = rewire(testModules.A),
someOtherModule,
mockedFs = {};
rewired = rewire("./testModules/privateModules/privateModuleA.js", null, null, leaks);
expect(rewired.__.myPrivateFunction()).to.be("Hello I'm very private");
rewired = rewire("./testModules/privateModules/privateModuleB.js", null, null, leaks);
expect(rewired.__.myPrivateFunction()).to.be("Hello I'm very private");
rewiredModuleA.__set__("fs", mockedFs);
someOtherModule = require(testModules.someOtherModule);
expect(someOtherModule.fs).not.to.be(mockedFs);
});
it("should leak nothing on demand", function () {
var rewired;
it("should provide the ability to mock global objects just within the module", function () {
var rewiredModuleA = rewire(testModules.A),
rewiredModuleB = rewire(testModules.B),
consoleMock = {},
processMock = {},
newFilename = "myFile.js";
rewired = rewire("./testModules/A/moduleA.js");
expect(rewired.__).to.be(undefined);
rewiredModuleA.__set__({
console: consoleMock,
process: processMock
});
rewiredModuleA.__set__("__filename", newFilename);
rewiredModuleB.__set__({
console: consoleMock,
process: processMock
});
rewiredModuleB.__set__("__filename", newFilename);
expect(rewiredModuleA.getConsole()).to.be(consoleMock);
expect(rewiredModuleB.getConsole()).to.be(consoleMock);
expect(console).not.to.be(consoleMock);
expect(rewiredModuleA.getProcess()).to.be(processMock);
expect(rewiredModuleB.getProcess()).to.be(processMock);
expect(process).not.to.be(processMock);
expect(rewiredModuleA.getFilename()).to.be(newFilename);
expect(rewiredModuleB.getFilename()).to.be(newFilename);
});

@@ -102,9 +125,7 @@ it("should cache the rewired module", function () {

rewired = rewire("./testModules/B/moduleB.js");
rewired.requireIndex();
expect(rewired.index.b).to.be(rewired);
rewired = rewire(testModules.someOtherModule);
expect(require(testModules.A).someOtherModule).to.be(rewired);
cleanRequireCache();
rewired = rewire("./testModules/B/moduleB.js", null, null, null, true);
rewired.requireIndex();
expect(rewired.index.b).to.be(rewired);
rewired = rewire(testModules.someOtherModule, true);
expect(require(testModules.A).someOtherModule).to.be(rewired);
});

@@ -114,26 +135,24 @@ it("should not cache the rewired module on demand", function () {

rewired = rewire("./testModules/B/moduleB.js", null, null, null, false);
rewired.requireIndex();
expect(rewired.index.b).not.to.be(rewired);
rewired = rewire(testModules.someOtherModule, false);
expect(require(testModules.A).someOtherModule).not.to.be(rewired);
});
it("should not influence the original node require if nothing has been required within the rewired module", function () {
var moduleCMock = {},
moduleB,
mocks = {
"../C/moduleC.js": moduleCMock
};
rewire("./testModules/C/moduleC.js", mocks); // nothing happens here because moduleC doesn't require anything
moduleB = require("./testModules/A/moduleA.js"); // if restoring the original node require didn't worked, the mock would be applied now
expect(moduleB.c).not.to.be(moduleCMock);
rewire(testModules.emptyModule); // nothing happens here because emptyModule doesn't require anything
expect(require(testModules.A).__set__).to.be(undefined); // if restoring the original node require didn't worked, the module would have a setter
});
it("subsequent calls of rewire should always return a new instance", function () {
expect(rewire(testModules.A)).not.to.be(rewire(testModules.A));
});
describe("#reset", function () {
it("should remove all rewired modules from cache", function () {
var rewired = rewire("./testModules/B/moduleB.js");
var rewiredModuleA = rewire(testModules.A),
rewiredModuleB = rewire(testModules.B);
expect(require("./testModules/B/moduleB.js")).to.be(rewired);
expect(require(testModules.A)).to.be(rewiredModuleA);
expect(require(testModules.B)).to.be(rewiredModuleB);
rewire.reset();
expect(require("./testModules/B/moduleB.js")).not.to.be(rewired);
expect(require(testModules.A)).not.to.be(rewiredModuleA);
expect(require(testModules.B)).not.to.be(rewiredModuleB);
});
});
});
"use strict"; // run code in ES5 strict mode
// Add a breakpoint on line 6 and on line 11 and debug "debug.test.js" to test if the IDE stops at these points.
// Watch also the variable someVar that is injected by rewire. It will be undefined at this point because
// all injections are executed at the end of the module.
// It's already visible because of hoisting: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/)
var someNumber = 0;
var myNumber = 0;
module.exports = function () {
// In this line someVar will be defined.
someNumber++;
someVar;
myNumber = 1;
};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc