Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/rewire.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/browserify/appendix.js44
-rw-r--r--lib/browserify/browserifyMiddleware.js61
-rw-r--r--lib/browserify/browserifyRewire.js76
-rw-r--r--lib/browserify/getRewireRequires.js16
-rw-r--r--lib/index.js2
-rw-r--r--lib/rewire.js18
-rw-r--r--package.json3
-rw-r--r--playground.js9
-rw-r--r--test/browser/index.html9
-rw-r--r--test/browserify.browserifyRewire.test.js126
-rw-r--r--test/browserify.getRewireRequires.test.js19
-rw-r--r--test/rewire.test.js167
-rw-r--r--test/testHelpers/createFakePackageJSON.js11
-rw-r--r--test/testHelpers/removeFakePackageJSON.js9
-rw-r--r--test/testModules/moduleA.js5
-rw-r--r--test/testModules/moduleB.js30
-rw-r--r--test/testModules/sharedTestCases.js175
17 files changed, 583 insertions, 197 deletions
diff --git a/lib/browserify/appendix.js b/lib/browserify/appendix.js
new file mode 100644
index 0000000..02fd9c1
--- /dev/null
+++ b/lib/browserify/appendix.js
@@ -0,0 +1,44 @@
+/**
+ * This code gets injected at the end of the browserify bundle via b.append().
+ */
+
+if (typeof window.browserifyRequire !== "undefined") {
+ throw new Error("Naming collision detected: window.browserifyRequire seems to be occupied.");
+}
+
+// Saves the browserifyRequire under a new name. Necessary to call the original browserifyRequire within
+// a module where the variable name "require" is overridden by the module's internal require.
+window.browserifyRequire = require;
+
+/**
+ * Provides a special require-proxy. Every module calls window.browserifyRequire.getProxy(require, __filename) at the
+ * beginning and overrides its own require with this proxy.
+ *
+ * This is necessary to call rewire() with the original __filename. Thus you can use rewire() like require().
+ *
+ * @param {!Function} internalRequire the module's own require
+ * @param {String} filename the __filename of the module
+ * @return {Function} requireProxy
+ */
+window.browserifyRequire.getProxy = function (internalRequire, filename) {
+ var rewireModule = internalRequire("rewire"),
+ key;
+
+ function rewireProxy(path, cache) {
+ return rewireModule(filename, path, cache);
+ }
+
+ for (key in rewireModule) {
+ if (rewireModule.hasOwnProperty(key)) {
+ rewireProxy[key] = rewireModule[key];
+ }
+ }
+
+ return function requireProxy(path) {
+ if (path === "rewire") {
+ return rewireProxy;
+ } else {
+ return internalRequire(path);
+ }
+ };
+}; \ No newline at end of file
diff --git a/lib/browserify/browserifyMiddleware.js b/lib/browserify/browserifyMiddleware.js
new file mode 100644
index 0000000..5b5e042
--- /dev/null
+++ b/lib/browserify/browserifyMiddleware.js
@@ -0,0 +1,61 @@
+var setterSrc = require("../__set__.js").toString(),
+ getterSrc = require("../__get__.js").toString(),
+ fs = require("fs"),
+ path = require("path"),
+ getImportGlobalsSrc = require("../getImportGlobalsSrc.js"),
+ getRewireRequires = require("./getRewireRequires.js"),
+ detectStrictMode = require("../detectStrictMode.js"),
+
+ appendix = fs.readFileSync(__dirname + "/appendix.js", "utf8"),
+ importGlobalsSrc = getImportGlobalsSrc(),
+ injectionSrc = getInjectionSrc().replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view
+
+function getInjectionSrc() {
+ return 'require("rewire").register(__filename, ' + setterSrc + ', ' + getterSrc + ');' +
+ 'process = require("__browserify_process");' +
+ 'require = window.browserifyRequire.getProxy(require, __filename);';
+}
+
+function browserifyMiddleware(b) {
+ var strictMode;
+
+ b.register(".js", function injectRewire(src, filename) {
+ var rewireRequires = getRewireRequires(src),
+ strictMode = "";
+
+ // Add all modules that are loaded by rewire() manually to browserify because browserify's
+ // require-sniffing doesn't work here.
+ rewireRequires.forEach(function forEachRewireRequire(requirePath) {
+
+ if (requirePath.charAt(0) === ".") {
+ requirePath = path.resolve(path.dirname(filename), requirePath);
+ }
+ b.require(requirePath);
+
+ });
+
+ if (detectStrictMode(src) === true) {
+ strictMode = ' "use strict"; ';
+ }
+
+ filename = filename.replace(/\\/g, "/");
+ if (filename.indexOf("/rewire/lib") === -1) {
+ src =
+ strictMode +
+ "var global = window; " +
+ importGlobalsSrc +
+ injectionSrc +
+ // For a better debugging experience we're adding a comment with the filename
+ "\n//// " + filename + " /////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n" +
+ src +
+ "\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n";
+ }
+
+ return src;
+ });
+ b.append(appendix);
+
+ return b;
+}
+
+module.exports = browserifyMiddleware; \ No newline at end of file
diff --git a/lib/browserify/browserifyRewire.js b/lib/browserify/browserifyRewire.js
new file mode 100644
index 0000000..59ba8cf
--- /dev/null
+++ b/lib/browserify/browserifyRewire.js
@@ -0,0 +1,76 @@
+var pathUtil = require("path"),
+ browserifyRequire = window.browserifyRequire;
+
+var registry = {},
+ rewiredModules = []; // cache for all rewired modules so it can be reset anytime
+
+function rewire(parentModulePath, targetPath, cache) {
+ var originalModule,
+ rewiredModule = {},
+ registeredTargetModule;
+
+ if (cache === undefined) {
+ cache = true;
+ }
+
+ // Make absolute paths
+ if (targetPath.charAt(0) === ".") {
+ targetPath = pathUtil.resolve(pathUtil.dirname(parentModulePath), targetPath);
+ }
+
+ // Normalize path with file extensions
+ targetPath = require.resolve(targetPath);
+
+ // Deleting module from cache to trigger execution again
+ delete browserifyRequire.modules[targetPath]._cached;
+
+ // Require module to trigger rewire.register() if it hasnt been required yet
+ // Putting (require) within brackets is a hack to disable browserifys require sniffing
+ // @see https://github.com/substack/node-browserify/issues/132#issuecomment-5281470
+ originalModule = (require)(targetPath);
+
+ for (var key in originalModule) {
+ if (originalModule.hasOwnProperty(key)) {
+ rewiredModule[key] = originalModule[key];
+ }
+ }
+
+ if (cache) {
+ browserifyRequire.modules[targetPath]._cached = rewiredModule;
+ }
+
+ // Get registry entry of the target module
+ registeredTargetModule = registry[targetPath];
+
+ // Apply setter and getters
+ rewiredModule.__set__ = registeredTargetModule.setter;
+ rewiredModule.__get__ = registeredTargetModule.getter;
+
+ // Store rewired modules for rewire.reset()
+ rewiredModules.push(targetPath);
+
+ return rewiredModule;
+}
+
+rewire.register = function (filename, setter, getter) {
+ registry[filename] = {
+ setter: setter,
+ getter: getter
+ };
+};
+
+/**
+ * Deletes all rewired modules from the cache
+ */
+rewire.reset = function () {
+ var modules = browserifyRequire.modules,
+ i;
+
+ for (i = 0; i < rewiredModules.length; i++) {
+ delete modules[rewiredModules[i]]._cached;
+ }
+
+ rewiredModules = [];
+};
+
+module.exports = rewire; \ No newline at end of file
diff --git a/lib/browserify/getRewireRequires.js b/lib/browserify/getRewireRequires.js
new file mode 100644
index 0000000..c8b0f01
--- /dev/null
+++ b/lib/browserify/getRewireRequires.js
@@ -0,0 +1,16 @@
+function getRewireRequires(src) {
+ var result = [],
+ regExp = /[^a-zA-Z0-9_]rewire\(["'](.+?)["']\)/g,
+ match;
+
+ src = " " + src; // ensure that rewire() is not at index 0 otherwise the regexp won't work in this case
+ match = regExp.exec(src);
+ while (match !== null) {
+ result.push(match[1]);
+ match = regExp.exec(src);
+ }
+
+ return result;
+}
+
+module.exports = getRewireRequires; \ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
index 0960dd6..6763399 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -22,7 +22,7 @@ function rewire(request, cache) {
if (process.title === "browser") {
module.exports = require("./browserify/browserifyRewire.js");
} else {
- // Putting (require) within brackets is a hack to disable browserify require sniffing
+ // Putting (require) within brackets is a hack to disable browserify's require sniffing
// @see https://github.com/substack/node-browserify/issues/132#issuecomment-5281470
rewireModule = (require)("./rewire.js");
diff --git a/lib/rewire.js b/lib/rewire.js
index 2a51e26..080847f 100644
--- a/lib/rewire.js
+++ b/lib/rewire.js
@@ -17,7 +17,7 @@ function restoreOriginalWrappers() {
/**
* Does actual rewiring the module. For further documentation @see index.js
*/
-function rewire(parentModule, filename, cache) {
+function rewire(parentModulePath, targetPath, cache) {
var testModule,
nodeRequire,
prepend,
@@ -37,21 +37,21 @@ function rewire(parentModule, filename, cache) {
}
// Checking params
- if (typeof filename !== "string") {
+ if (typeof targetPath !== "string") {
throw new TypeError("Filename must be a string");
}
// Resolve full filename relative to the parent module
- filename = Module._resolveFilename(filename, parentModule);
+ targetPath = Module._resolveFilename(targetPath, parentModulePath);
// Special support for older node versions that returned an array on Module._resolveFilename
// @see https://github.com/joyent/node/blob/865b077819a9271a29f982faaef99dc635b57fbc/lib/module.js#L319
- if (Array.isArray(filename)) {
- filename = filename[1];
+ if (Array.isArray(targetPath)) {
+ targetPath = targetPath[1];
}
// Create testModule as it would be created by require()
- testModule = new Module(filename, parentModule);
+ testModule = new Module(targetPath, parentModulePath);
// Patching requireProxy
nodeRequire = testModule.require;
@@ -66,7 +66,7 @@ function rewire(parentModule, filename, cache) {
// Check if the module uses the strict mode.
// If so we must ensure that "use strict"; stays at the beginning of the module.
- src = fs.readFileSync(filename, "utf8");
+ src = fs.readFileSync(targetPath, "utf8");
if (detectStrictMode(src) === true) {
prepend = ' "use strict"; ' + prepend;
}
@@ -82,8 +82,8 @@ function rewire(parentModule, filename, cache) {
// 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(targetPath); // save in private cache for .reset()
+ require.cache[targetPath] = testModule;
}
// This is only necessary if nothing has been required within the module
diff --git a/package.json b/package.json
index fc41074..9b5cf20 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,8 @@
},
"devDependencies": {
"mocha": "1.2.x",
- "expect.js": "0.1.x"
+ "expect.js": "0.1.x",
+ "browserify": "1.13.x"
},
"scripts" : {
"test" : "mocha"
diff --git a/playground.js b/playground.js
new file mode 100644
index 0000000..2ec9989
--- /dev/null
+++ b/playground.js
@@ -0,0 +1,9 @@
+var vm = require("vm");
+
+var mine = {};
+
+mine.runInNewContext = vm.runInNewContext;
+
+mine.runInNewContext("console.log('test');", {
+ "console": console
+});
diff --git a/test/browser/index.html b/test/browser/index.html
new file mode 100644
index 0000000..46d63d9
--- /dev/null
+++ b/test/browser/index.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<head>
+ <link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
+ <script src="../../node_modules/mocha/mocha.js" type="text/javascript"></script>
+ <script src="browseroutput.js" type="text/javascript"></script>
+</head>
+<body>
+ <div id="mocha"></div>
+</body> \ No newline at end of file
diff --git a/test/browserify.browserifyRewire.test.js b/test/browserify.browserifyRewire.test.js
new file mode 100644
index 0000000..cf8dbd9
--- /dev/null
+++ b/test/browserify.browserifyRewire.test.js
@@ -0,0 +1,126 @@
+var vm = require("vm"),
+ fs = require("fs"),
+ pathUtil = require("path"),
+ expect = require("expect.js"),
+ browserify = require("browserify"),
+ browserifyMiddleware = require("../lib/index.js").browserify;
+
+/**
+ * Executes the source in a context that pretends to be a browser
+ * @param {!String} src
+ */
+function runInFakeBrowserContext(src, filename) {
+ vm.runInNewContext(src, {
+ window: {
+ console: console,
+ describe: describe,
+ it: it,
+ before: before,
+ after: after,
+ beforeEach: beforeEach,
+ afterEach: afterEach,
+ setTimeout: setTimeout
+ },
+ console: console
+ }, filename);
+}
+
+describe("browserifyRewire", function () {
+ before(require("./testHelpers/createFakePackageJSON.js"));
+ after(require("./testHelpers/removeFakePackageJSON.js"));
+ it("should attach __set__ and __get__ to the exports-obj", function (done) {
+ var context,
+ exportsObj = {},
+ returnedObj,
+ browserifyRewire;
+
+ // Register with fake objects
+ // Using null for objects that are not involved in this particular test
+ function moduleA() {
+ "use strict";
+
+ browserifyRewire.register("/a.js", null, null);
+ returnedObj = browserifyRewire("/a.js", "/b.js");
+ }
+
+ function moduleB() {
+ "use strict";
+ browserifyRewire.register("/b.js", setter, getter);
+
+ return exportsObj;
+ }
+
+ function fakeResolve() {
+ return "/b.js";
+ }
+
+ function fakeRequire(requirePath) {
+ if (requirePath === "path") {
+ return pathUtil;
+ } else {
+ return moduleB();
+ }
+ }
+ fakeRequire.resolve = fakeResolve;
+
+ function setter() {}
+ function getter() {}
+
+ context = {
+ require: fakeRequire,
+ module: {},
+ console: console,
+ window: {
+ browserifyRequire: {
+ modules: {
+ "/b.js": {
+ _cached : {}
+ }
+ }
+ }
+ }
+ };
+
+ fs.readFile(pathUtil.resolve(__dirname, "../lib/browserify/browserifyRewire.js"), "utf8", function onBrowserifyRewireRead(err, src) {
+ vm.runInNewContext(src, context);
+ browserifyRewire = context.module.exports;
+
+ moduleA();
+
+ expect(returnedObj).not.to.be(exportsObj);
+ expect(returnedObj.__set__).to.be(setter);
+ expect(returnedObj.__get__).to.be(getter);
+ expect(context.window.browserifyRequire.modules["/b.js"]._cached).to.be(returnedObj);
+
+ done();
+ });
+ });
+ it("should run all sharedTestCases without exception", function (done) {
+ var b = browserify(),
+ browserOutput = __dirname + "/browser/browseroutput.js",
+ browserBundle,
+ vmBundle;
+
+ b.use(browserifyMiddleware);
+ b.require(__dirname + "/testModules/sharedTestCases.js");
+ vmBundle = b.bundle();
+ browserBundle = vmBundle;
+
+ // Setup for mocha
+ browserBundle += 'window.onload = function () {' +
+ 'mocha.setup("bdd");' +
+ 'window.browserifyRequire("/test/testModules/sharedTestCases.js");' +
+ 'mocha.run();' +
+ '};';
+
+ vmBundle += 'window.browserifyRequire("/test/testModules/sharedTestCases.js");';
+
+ // Output for browser-testing
+ fs.mkdir(__dirname + "/browser", function onMkDir() {
+ fs.writeFile(browserOutput, browserBundle, "utf8", done);
+
+ // This should throw no exception.
+ runInFakeBrowserContext(vmBundle, browserOutput);
+ });
+ });
+}); \ No newline at end of file
diff --git a/test/browserify.getRewireRequires.test.js b/test/browserify.getRewireRequires.test.js
new file mode 100644
index 0000000..98673cc
--- /dev/null
+++ b/test/browserify.getRewireRequires.test.js
@@ -0,0 +1,19 @@
+var expect = require("expect.js"),
+ getRewireRequires = require("../lib/browserify/getRewireRequires.js");
+
+describe("getRewireRequires", function () {
+ it("should detect a single rewire()", function () {
+ var src = "rewire('aaa/bbb/ccc.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js"]);
+ });
+ it("should detect multiple rewire()", function () {
+ var src = "var aaa = rewire('aaa/bbb/ccc.js'); var bbb = rewire('bbb/ccc/ddd.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
+
+ src = "rewire('aaa/bbb/ccc.js'); rewire('bbb/ccc/ddd.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
+ });
+}); \ No newline at end of file
diff --git a/test/rewire.test.js b/test/rewire.test.js
index fa17088..1783ad5 100644
--- a/test/rewire.test.js
+++ b/test/rewire.test.js
@@ -2,169 +2,10 @@
// In case this module was in strict mode, all other modules called by this would also be strict.
// But when testing if the strict mode is preserved, we must ensure that this module is NOT strict.
-var path = require("path"),
- expect = require("expect.js"),
- rewire = require("../lib/index.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"),
- strictModule: path.resolve(__dirname, "./testModules/strictModule.js")
- };
-
-
-function checkForTypeError(err) {
- expect(err.constructor).to.be(TypeError);
-}
-
-function cleanRequireCache() {
- var moduleName,
- modulePath;
-
- for (moduleName in testModules) {
- if (testModules.hasOwnProperty(moduleName)) {
- modulePath = testModules[moduleName];
- delete require.cache[modulePath];
- }
- }
-}
-
describe("rewire", function () {
- beforeEach(cleanRequireCache); // ensuring a clean test environment
- 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 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);
-
- 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 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 = {};
-
- 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);
- rewiredModuleA.__set__("env", "ENVENV");
- });
- it("should provide the ability to get private vars", function () {
- var rewiredModuleA = rewire(testModules.A);
-
- expect(rewiredModuleA.__get__("myNumber")).to.be(rewiredModuleA.getMyNumber());
- expect(rewiredModuleA.__get__("myObj")).to.be(rewiredModuleA.getMyObj());
- });
- 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();
- }
- };
-
- rewiredModuleA.__set__("fs", mockedFs);
- rewiredModuleA.readFileSync();
- });
- it("should not influence other modules when injecting mocks", function () {
- var rewiredModuleA = rewire(testModules.A),
- someOtherModule,
- mockedFs = {};
-
- rewiredModuleA.__set__("fs", mockedFs);
- someOtherModule = require(testModules.someOtherModule);
- expect(someOtherModule.fs).not.to.be(mockedFs);
- });
- 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";
-
- 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);
- });
- it("should cache the rewired module", function () {
- var rewired;
-
- rewired = rewire(testModules.someOtherModule);
- expect(require(testModules.A).someOtherModule).to.be(rewired);
- cleanRequireCache();
- rewired = rewire(testModules.someOtherModule, true);
- expect(require(testModules.A).someOtherModule).to.be(rewired);
- });
- it("should not cache the rewired module on demand", function () {
- var 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 () {
- 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));
- });
- it("should preserve the strict mode", function () {
- var strictModule = rewire(testModules.strictModule);
-
- expect(function () {
- strictModule.doSomethingUnstrict();
- }).to.throwException(checkForTypeError);
- });
- describe("#reset", function () {
- it("should remove all rewired modules from cache", function () {
- var rewiredModuleA = rewire(testModules.A),
- rewiredModuleB = rewire(testModules.B);
-
- expect(require(testModules.A)).to.be(rewiredModuleA);
- expect(require(testModules.B)).to.be(rewiredModuleB);
- rewire.reset();
- expect(require(testModules.A)).not.to.be(rewiredModuleA);
- expect(require(testModules.B)).not.to.be(rewiredModuleB);
- });
+ before(require("./testHelpers/createFakePackageJSON.js"));
+ after(require("./testHelpers/removeFakePackageJSON.js"));
+ it("should pass all shared test cases", function () {
+ require("./testModules/sharedTestCases.js");
});
}); \ No newline at end of file
diff --git a/test/testHelpers/createFakePackageJSON.js b/test/testHelpers/createFakePackageJSON.js
new file mode 100644
index 0000000..dbda04f
--- /dev/null
+++ b/test/testHelpers/createFakePackageJSON.js
@@ -0,0 +1,11 @@
+var fs = require("fs"),
+ pathUtil = require("path"),
+ nodeModulesDir = pathUtil.resolve(__dirname, "../../node_modules");
+
+module.exports = function createFakePackageJSON(done) {
+ var fakePackageJSON = '{ "main": "../../lib/index.js" }';
+
+ fs.mkdir(nodeModulesDir + "/rewire", function onMkDir() {
+ fs.writeFile(nodeModulesDir + "/rewire/package.json", fakePackageJSON, "utf8", done);
+ });
+}; \ No newline at end of file
diff --git a/test/testHelpers/removeFakePackageJSON.js b/test/testHelpers/removeFakePackageJSON.js
new file mode 100644
index 0000000..676339e
--- /dev/null
+++ b/test/testHelpers/removeFakePackageJSON.js
@@ -0,0 +1,9 @@
+var fs = require("fs"),
+ pathUtil = require("path"),
+ nodeModulesDir = pathUtil.resolve(__dirname, "../../node_modules");
+
+module.exports = function removeFakePackageJSON(done) {
+ fs.unlink(nodeModulesDir + "/rewire/package.json", function onPackageJSONUnlink() {
+ fs.rmdir(nodeModulesDir + "/rewire", done);
+ });
+}; \ No newline at end of file
diff --git a/test/testModules/moduleA.js b/test/testModules/moduleA.js
index 87f4949..fd665f7 100644
--- a/test/testModules/moduleA.js
+++ b/test/testModules/moduleA.js
@@ -29,7 +29,7 @@ function readFileSync() {
function checkSomeGlobals() {
if (typeof global === "undefined") {
- //throw new ReferenceError("global is undefined");
+ throw new ReferenceError("global is undefined");
}
if (typeof process === "undefined") {
throw new ReferenceError("process is undefined");
@@ -37,9 +37,6 @@ function checkSomeGlobals() {
if (typeof console === "undefined") {
throw new ReferenceError("console is undefined");
}
- if (typeof Buffer === "undefined") {
- throw new ReferenceError("Buffer is undefined");
- }
if (typeof __filename === "undefined") {
throw new ReferenceError("__filename is undefined");
}
diff --git a/test/testModules/moduleB.js b/test/testModules/moduleB.js
index c9fec13..fd665f7 100644
--- a/test/testModules/moduleB.js
+++ b/test/testModules/moduleB.js
@@ -3,6 +3,7 @@
var someOtherModule = require("./someOtherModule.js"),
myNumber = 0, // copy by value
myObj = {}, // copy by reference
+ env = "bla",
fs = require("fs");
// We need getters and setters for private vars to check if our injected setters and getters actual work
@@ -36,9 +37,6 @@ function checkSomeGlobals() {
if (typeof console === "undefined") {
throw new ReferenceError("console is undefined");
}
- if (typeof Buffer === "undefined") {
- throw new ReferenceError("Buffer is undefined");
- }
if (typeof __filename === "undefined") {
throw new ReferenceError("__filename is undefined");
}
@@ -62,20 +60,14 @@ function getFilename() {
return __filename;
}
-function main() {
-
-}
-
-main.setMyNumber = setMyNumber;
-main.getMyNumber = getMyNumber;
-main.setMyObj = setMyObj;
-main.getMyObj = getMyObj;
-main.readFileSync = readFileSync;
-main.checkSomeGlobals = checkSomeGlobals;
-main.getConsole = getConsole;
-main.getProcess = getProcess;
-main.getFilename = getFilename;
-main.someOtherModule = someOtherModule;
-
// different styles of exports in moduleA.js and moduleB.js
-module.exports = main;
+exports.setMyNumber = setMyNumber;
+exports.getMyNumber = getMyNumber;
+exports.setMyObj = setMyObj;
+exports.getMyObj = getMyObj;
+exports.readFileSync = readFileSync;
+exports.checkSomeGlobals = checkSomeGlobals;
+exports.getConsole = getConsole;
+exports.getProcess = getProcess;
+exports.getFilename = getFilename;
+exports.someOtherModule = someOtherModule; \ No newline at end of file
diff --git a/test/testModules/sharedTestCases.js b/test/testModules/sharedTestCases.js
new file mode 100644
index 0000000..01f7e7b
--- /dev/null
+++ b/test/testModules/sharedTestCases.js
@@ -0,0 +1,175 @@
+// Don't run code in ES5 strict mode.
+// In case this module was in strict mode, all other modules called by this would also be strict.
+// But when testing if the strict mode is preserved, we must ensure that this module is NOT strict.
+
+var path = require("path"),
+ expect = require("expect.js"),
+ rewire = require("rewire");
+
+var testModules = {
+ A: path.resolve(__dirname, "./moduleA.js"),
+ B: path.resolve(__dirname, "./moduleB.js"),
+ someOtherModule: path.resolve(__dirname, "./someOtherModule.js"),
+ emptyModule: path.resolve(__dirname, "./emptyModule.js"),
+ strictModule: path.resolve(__dirname, "./strictModule.js")
+ };
+
+
+function checkForTypeError(err) {
+ expect(err.constructor).to.be(TypeError);
+}
+
+function cleanRequireCache() {
+ var moduleName,
+ modulePath;
+
+ for (moduleName in testModules) {
+ if (testModules.hasOwnProperty(moduleName)) {
+ modulePath = testModules[moduleName];
+ if (typeof window === "undefined") {
+ delete require.cache[modulePath];
+ } else {
+ if (typeof window.browserifyRequire.modules[modulePath]._cached === "object") {
+ delete window.browserifyRequire.modules[modulePath]._cached;
+ }
+ }
+ }
+ }
+}
+
+describe("rewire " + (typeof window === "undefined"? "in node.js": "in the browser"), function () {
+ beforeEach(cleanRequireCache); // ensuring a clean test environment
+ it("should work like require()", function () {
+ expect(rewire("./moduleA.js")).to.be(require("./moduleA.js"));
+ cleanRequireCache();
+ expect(rewire("../testModules/moduleA.js")).to.be(require("../testModules/moduleA.js"));
+ cleanRequireCache();
+ expect(rewire("./moduleA.js")).to.be(require("./moduleA.js"));
+ });
+ it("should modify the module so it provides a __set__ - function", function () {
+ expect(rewire("./moduleA.js").__set__).to.be.a(Function);
+ expect(rewire("./moduleB.js").__set__).to.be.a(Function);
+ });
+ it("should modify the module so it provides a __get__ - function", function () {
+ expect(rewire("./moduleA.js").__get__).to.be.a(Function);
+ expect(rewire("./moduleB.js").__get__).to.be.a(Function);
+ });
+ it("should not influence other modules", function () {
+ var rewiredModuleA = rewire("./moduleA.js");
+
+ expect(require("./someOtherModule.js").__set__).to.be(undefined);
+ expect(require("./someOtherModule.js").__get__).to.be(undefined);
+ expect(require("fs").__set__).to.be(undefined);
+ expect(require("fs").__get__).to.be(undefined);
+ });
+ it("should not influence global objects by default", function () {
+ // This should throw no exception
+ rewire("./moduleA.js").checkSomeGlobals();
+ rewire("./moduleB.js").checkSomeGlobals();
+ });
+ it("should provide the ability to set private vars", function () {
+ var rewiredModuleA = rewire("./moduleA.js"),
+ newObj = {};
+
+ 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);
+ rewiredModuleA.__set__("env", "ENVENV");
+ });
+ it("should provide the ability to get private vars", function () {
+ var rewiredModuleA = rewire("./moduleA.js");
+
+ expect(rewiredModuleA.__get__("myNumber")).to.be(rewiredModuleA.getMyNumber());
+ expect(rewiredModuleA.__get__("myObj")).to.be(rewiredModuleA.getMyObj());
+ });
+ it("should provide the ability to inject mocks", function (done) {
+ var rewiredModuleA = rewire("./moduleA.js"),
+ mockedFs = {
+ readFileSync: function (file) {
+ expect(file).to.be("bla.txt");
+ done();
+ }
+ };
+
+ rewiredModuleA.__set__("fs", mockedFs);
+ rewiredModuleA.readFileSync();
+ });
+ it("should not influence other modules when injecting mocks", function () {
+ var rewiredModuleA = rewire("./moduleA.js"),
+ someOtherModule,
+ mockedFs = {};
+
+ rewiredModuleA.__set__("fs", mockedFs);
+ someOtherModule = require("./someOtherModule.js");
+ expect(someOtherModule.fs).not.to.be(mockedFs);
+ });
+ it("should provide the ability to mock global objects just within the module", function () {
+ var rewiredModuleA = rewire("./moduleA.js"),
+ rewiredModuleB = rewire("./moduleB.js"),
+ consoleMock = {},
+ processMock = {},
+ newFilename = "myFile.js";
+
+ 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);
+ });
+ it("should cache the rewired module", function () {
+ var rewired;
+
+ rewired = rewire("./someOtherModule.js");
+ expect(require("./moduleA.js").someOtherModule).to.be(rewired);
+ cleanRequireCache();
+ rewired = rewire("./someOtherModule.js", true);
+ expect(require("./moduleA.js").someOtherModule).to.be(rewired);
+ });
+ it("should not cache the rewired module on demand", function () {
+ var rewired;
+
+ rewired = rewire("./someOtherModule.js", false);
+ expect(require("./moduleA.js").someOtherModule).not.to.be(rewired);
+ });
+ it("should not influence the original node require if nothing has been required within the rewired module", function () {
+ rewire("./emptyModule.js"); // nothing happens here because emptyModule doesn't require anything
+ expect(require("./moduleA.js").__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("./moduleA.js")).not.to.be(rewire("./moduleA.js"));
+ });
+ it("should preserve the strict mode", function () {
+ var strictModule = rewire("./strictModule.js");
+
+ expect(function () {
+ strictModule.doSomethingUnstrict();
+ }).to.throwException(checkForTypeError);
+ });
+ describe("#reset", function () {
+ it("should remove all rewired modules from cache", function () {
+ var rewiredModuleA = rewire("./moduleA.js"),
+ rewiredModuleB = rewire("./moduleB.js");
+
+ expect(require("./moduleA.js")).to.be(rewiredModuleA);
+ expect(require("./moduleB.js")).to.be(rewiredModuleB);
+ rewire.reset();
+ expect(require("./moduleA.js")).not.to.be(rewiredModuleA);
+ expect(require("./moduleB.js")).not.to.be(rewiredModuleB);
+ });
+ });
+}); \ No newline at end of file