Skip to content

Commit

Permalink
Merge 8b2ec0d into cce2de8
Browse files Browse the repository at this point in the history
  • Loading branch information
killmenot committed Nov 12, 2017
2 parents cce2de8 + 8b2ec0d commit 5e3a4e1
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 33 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -5,7 +5,7 @@ rewire
[![](https://img.shields.io/npm/v/rewire.svg)](https://www.npmjs.com/package/rewire)
[![](https://img.shields.io/npm/dm/rewire.svg)](https://www.npmjs.com/package/rewire)
[![Dependency Status](https://david-dm.org/jhnns/rewire.svg)](https://david-dm.org/jhnns/rewire)
[![Build Status](https://travis-ci.org/jhnns/rewire.svg?branch=master)](https://travis-ci.org/rewire/jhnns)
[![Build Status](https://travis-ci.org/jhnns/rewire.svg?branch=master)](https://travis-ci.org/jhnns/rewire)
[![Coverage Status](https://img.shields.io/coveralls/jhnns/rewire.svg)](https://coveralls.io/r/jhnns/rewire?branch=master)

rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may
Expand Down Expand Up @@ -88,6 +88,10 @@ myModule.__set__({
You may also override globals. These changes are only within the module, so you don't have to be concerned that other modules are influenced by your mock.

```javascript
var options = {
overridable: ["console", "process"]
};
var myModule = rewire("../lib/myModule.js", options);
myModule.__set__({
console: {
log: function () { /* be quiet */ }
Expand Down
18 changes: 9 additions & 9 deletions lib/getImportGlobalsSrc.js
Expand Up @@ -7,32 +7,32 @@
*
* @return {String}
*/
function getImportGlobalsSrc(ignore) {
function getImportGlobalsSrc(overridable) {
var key,
value,
src = "",
ignore = [],
globalObj = typeof global === "undefined"? window: global;

ignore = ignore || [];
// global itself can't be overridden because it's the only reference to our real global objects
ignore.push("global");
// ignore 'module', 'exports' and 'require' on the global scope, because otherwise our code would
// shadow the module-internal variables
// @see https://github.com/jhnns/rewire-webpack/pull/6
ignore.push("module", "exports", "require");

for (key in globalObj) { /* jshint forin: false */
(overridable || []).forEach(function forEachKey(key) {
if (ignore.indexOf(key) !== -1) {
continue;
return;
}
value = globalObj[key];

// key may be an invalid variable name (e.g. 'a-b')
try {
eval("var " + key + ";");
src += "var " + key + " = global." + key + "; ";
// jshint -W061
eval("var " + key + ";");
// jshint +W061
src += "var " + key + " = global." + key + "; ";
} catch(e) {}
}
});

return src;
}
Expand Down
5 changes: 3 additions & 2 deletions lib/index.js
Expand Up @@ -5,10 +5,11 @@ 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} options Options.
* @return {*} the rewired module
*/
function rewire(filename) {
return rewireModule(module.parent, filename);
function rewire(filename, options) {
return rewireModule(module.parent, filename, options);
}

module.exports = rewire;
Expand Down
6 changes: 4 additions & 2 deletions lib/rewire.js
Expand Up @@ -9,7 +9,7 @@ var Module = require("module"),
/**
* Does actual rewiring the module. For further documentation @see index.js
*/
function internalRewire(parentModulePath, targetPath) {
function internalRewire(parentModulePath, targetPath, options) {
var targetModule,
prelude,
appendix,
Expand All @@ -20,14 +20,16 @@ function internalRewire(parentModulePath, targetPath) {
throw new TypeError("Filename must be a string");
}

options = options || {};

// Resolve full filename relative to the parent module
targetPath = Module._resolveFilename(targetPath, parentModulePath);

// Create testModule as it would be created by require()
targetModule = new Module(targetPath, parentModulePath);

// We prepend a list of all globals declared with var so they can be overridden (without changing original globals)
prelude = getImportGlobalsSrc();
prelude = getImportGlobalsSrc(options.overridable);

// Wrap module src inside IIFE so that function declarations do not clash with global variables
// @see https://github.com/jhnns/rewire/issues/56
Expand Down
59 changes: 44 additions & 15 deletions test/getImportGlobalsSrc.test.js
Expand Up @@ -3,7 +3,7 @@ var expect = require("expect.js"),
getImportGlobalsSrc = require("../lib/getImportGlobalsSrc.js");

describe("getImportGlobalsSrc", function () {
it("should declare all globals with a var", function () {
it("should declare no globals with a var", function () {
var context = {
global: global
},
Expand All @@ -18,44 +18,73 @@ describe("getImportGlobalsSrc", function () {
global.require = require;

// Also make sure it ignores invalid variable names
global['a-b'] = true;
global["a-b"] = true;

src = getImportGlobalsSrc();

delete global.module;
delete global.exports;
delete global.require;
delete global['__core-js_shared__'];
delete global['a-b'];
delete global["__core-js_shared__"];
delete global["a-b"];

expectedGlobals = Object.keys(global);
expectedGlobals = ["global"];

vm.runInNewContext(src, context);
actualGlobals = Object.keys(context);
actualGlobals.sort();
expectedGlobals.sort();
expect(actualGlobals).to.eql(expectedGlobals);
expect(actualGlobals.length).to.be.above(1);
});
it("should ignore the given variables", function () {
it("should declare overridable globals with a var", function () {
var context = {
global: global
},
ignore = ["console", "setTimeout"],
expectedGlobals,
overridable = ["clearTimeout", "setTimeout"],
src,
actualGlobals;

// Temporarily set module-internal variables on the global scope to check if getImportGlobalsSrc()
// ignores them properly
global.module = module;
global.exports = exports;
global.require = require;

// Also make sure it ignores invalid variable names
global["a-b"] = true;

src = getImportGlobalsSrc(overridable);

delete global.module;
delete global.exports;
delete global.require;
delete global["__core-js_shared__"];
delete global["a-b"];

expectedGlobals = ["clearTimeout", "global", "setTimeout"];

vm.runInNewContext(src, context);
actualGlobals = Object.keys(context);
actualGlobals.sort();
expectedGlobals.sort();
expect(actualGlobals).to.eql(expectedGlobals);
});
it("should ignore module-internal variables variables", function () {
var context = {
global: global
},
overridable = ["module", "exports", "require"],
src,
actualGlobals,
expectedGlobals = Object.keys(global);
expectedGlobals = ["global"];

src = getImportGlobalsSrc(overridable);

// getImportGlobalsSrc modifies the ignore array, so let's create a copy
src = getImportGlobalsSrc(ignore.slice(0));
expectedGlobals = expectedGlobals.filter(function filterIgnoredVars(value) {
return ignore.indexOf(value) === -1;
});
vm.runInNewContext(src, context);
actualGlobals = Object.keys(context);
actualGlobals.sort();
expectedGlobals.sort();
expect(actualGlobals).to.eql(expectedGlobals);
expect(actualGlobals.length).to.be.above(1);
});
});
15 changes: 11 additions & 4 deletions testLib/sharedTestCases.js
Expand Up @@ -161,8 +161,11 @@ module.exports = function () {
});

it("should provide the ability to mock global objects just within the module", function () {
var rewiredModuleA = rewire("./moduleA.js"),
rewiredModuleB = rewire("./moduleB.js"),
var options = {
overridable: ["console", "__filename", "Buffer", "document"]
},
rewiredModuleA = rewire("./moduleA.js", options),
rewiredModuleB = rewire("./moduleB.js", options),
consoleMock = {},
bufferMock = {},
documentMock = {},
Expand Down Expand Up @@ -196,14 +199,18 @@ module.exports = function () {

if (typeof window === "undefined") {
global.someGlobalVar = "test";
rewiredModule = rewire("./moduleA.js");
rewiredModule = rewire("./moduleA.js", {
overridable: ["someGlobalVar"]
});
rewiredModule.__set__("someGlobalVar", "other value");
expect(global.someGlobalVar).to.be("test");
expect(rewiredModule.__get__("someGlobalVar")).to.be("other value");
delete global.someGlobalVar;
} else {
window.someGlobalVar = "test";
rewiredModule = rewire("./moduleA.js");
rewiredModule = rewire("./moduleA.js", {
overridable: ["someGlobalVar"]
});
rewiredModule.__set__("someGlobalVar", "other value");
expect(window.someGlobalVar).to.be("test");
expect(rewiredModule.__get__("someGlobalVar")).to.be("other value");
Expand Down

0 comments on commit 5e3a4e1

Please sign in to comment.