From 8b2ec0daa2773e2a674da88211d712ed54a73cc2 Mon Sep 17 00:00:00 2001 From: Alexey Kucherenko Date: Sun, 12 Nov 2017 17:43:06 +0300 Subject: [PATCH] introduce overridable --- README.md | 6 +++- lib/getImportGlobalsSrc.js | 18 +++++----- lib/index.js | 5 +-- lib/rewire.js | 6 ++-- test/getImportGlobalsSrc.test.js | 59 ++++++++++++++++++++++++-------- testLib/sharedTestCases.js | 15 +++++--- 6 files changed, 76 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index c8a589d..39eccd5 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 */ } diff --git a/lib/getImportGlobalsSrc.js b/lib/getImportGlobalsSrc.js index 3c29c56..22d06ba 100644 --- a/lib/getImportGlobalsSrc.js +++ b/lib/getImportGlobalsSrc.js @@ -7,13 +7,12 @@ * * @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 @@ -21,18 +20,19 @@ function getImportGlobalsSrc(ignore) { // @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; } diff --git a/lib/index.js b/lib/index.js index 0edcd2c..3a3fe24 100644 --- a/lib/index.js +++ b/lib/index.js @@ -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; diff --git a/lib/rewire.js b/lib/rewire.js index e678f37..203f4bc 100644 --- a/lib/rewire.js +++ b/lib/rewire.js @@ -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, @@ -20,6 +20,8 @@ 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); @@ -27,7 +29,7 @@ function internalRewire(parentModulePath, targetPath) { 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 diff --git a/test/getImportGlobalsSrc.test.js b/test/getImportGlobalsSrc.test.js index 0c40e5a..9faa7a9 100644 --- a/test/getImportGlobalsSrc.test.js +++ b/test/getImportGlobalsSrc.test.js @@ -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 }, @@ -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); }); }); diff --git a/testLib/sharedTestCases.js b/testLib/sharedTestCases.js index b6caf6a..c62a3a3 100644 --- a/testLib/sharedTestCases.js +++ b/testLib/sharedTestCases.js @@ -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 = {}, @@ -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");