rewire
Advanced tools
Comparing version 0.3.0 to 0.3.1
@@ -14,9 +14,9 @@ /** | ||
arguments.varName = arguments[0]; | ||
if (typeof arguments.varName !== "string" || arguments.varName.length === 0) { | ||
if (arguments.varName && typeof arguments.varName === "string") { | ||
return eval(arguments.varName); | ||
} else { | ||
throw new TypeError("__get__ expects a non-empty string"); | ||
} | ||
return eval(arguments.varName); | ||
} | ||
module.exports = __get__; |
@@ -23,3 +23,3 @@ /** | ||
if (typeof arguments[0] === "object") { | ||
if (typeof arguments[0] === "object" && arguments.length === 1) { | ||
arguments.env = arguments.varName; | ||
@@ -29,8 +29,9 @@ if (!arguments.env || Array.isArray(arguments.env)) { | ||
} | ||
for (arguments.key in arguments.env) { | ||
if (arguments.env.hasOwnProperty(arguments.key)) { | ||
arguments.src += arguments.checkExistsSrc(arguments.key) + arguments.key + " = arguments.env." + arguments.key + ";"; | ||
for (arguments.varName in arguments.env) { | ||
if (arguments.env.hasOwnProperty(arguments.varName)) { | ||
arguments.varValue = arguments.env[arguments.varName]; | ||
arguments.src += arguments.checkExistsSrc(arguments.varName, arguments.varValue) + arguments.varName + " = arguments.env." + arguments.varName + ";"; | ||
} | ||
} | ||
} else if (typeof arguments.varName === "string") { | ||
} else if (typeof arguments.varName === "string" && arguments.length === 2) { | ||
if (!arguments.varName) { | ||
@@ -37,0 +38,0 @@ throw new TypeError("__set__ expects a non-empty string as a variable name"); |
@@ -9,4 +9,2 @@ var setterSrc = require("../__set__.js").toString(), | ||
browserInit = fs.readFileSync(__dirname + "/browserInit.js", "utf8"), | ||
importGlobalsSrc = getImportGlobalsSrc(), | ||
injectionSrc = getInjectionSrc().replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view | ||
@@ -23,14 +21,24 @@ | ||
function getInjectionSrc() { | ||
// Registers the setters and getters of every module according to their filename. The setters and getters must be | ||
// injected as string here to gain access to the private scope of the module. | ||
return 'require("rewire").register(__filename, ' + setterSrc + ', ' + getterSrc + ');' + | ||
// Overrides the module internal require with a require proxy. This proxy is necessary to call rewire with the | ||
// module's filename at the first parameter to resolve the path. This way rewire() works exactly like require(). | ||
'require = window.browserifyRequire.getProxy(require, __filename);'; | ||
return 'var rewire = require("rewire"); ' + | ||
// Registers the setters and getters of every module according to their filename. The setters and getters must be | ||
// injected as string here to gain access to the private scope of the module. | ||
'rewire.register(__filename, module, ' + setterSrc + ', ' + getterSrc + ');' + | ||
// Overrides the module internal require with a require proxy. This proxy is necessary to call rewire with the | ||
// module's filename at the first parameter to resolve the path. This way rewire() works exactly like require(). | ||
'require = rewire.getProxy(require, __dirname);' + | ||
// Cleaning up | ||
'rewire = undefined;'; | ||
} | ||
function browserifyMiddleware(b) { | ||
/** | ||
* Gets called for every module. Injects special code so rewire is able to access private variables. | ||
* | ||
* @param {String} src | ||
* @param {String} filename | ||
* @return {String} | ||
*/ | ||
function injectRewire(src, filename) { | ||
var rewireRequires, | ||
strictMode = ""; | ||
var rewireRequires; | ||
@@ -50,10 +58,7 @@ // Search for all rewire() statements an return the required path. | ||
// If the module uses strict mode we must ensure that "use strict" stays at the beginning of the module. | ||
if (detectStrictMode(src) === true) { | ||
strictMode = ' "use strict"; '; | ||
// Convert back slashes to normal slashes on windows. | ||
if (process.platform.indexOf("win") === 0) { | ||
filename = filename.replace(/\\/g, "/"); | ||
} | ||
// Convert back slashes to normal slashes. | ||
filename = filename.replace(/\\/g, "/"); | ||
// We don't want to inject this code at the beginning of a rewire/lib-module. Otherwise | ||
@@ -63,8 +68,26 @@ // it would cause a black hole that devours our universe. | ||
src = | ||
strictMode + // either '' or ' "use strict"; ' | ||
"/* this line was injected by rewire() */" + | ||
"var global = window; " + // window is our new global object | ||
importGlobalsSrc + | ||
// Trying to hide the injected line in the debug view with extra whitespaces. | ||
' ' + | ||
'/* this line was injected by rewire() */ ' + // Comment for the curious developer | ||
// Now all global variables are declared with a var statement so they can be changed via __set__() | ||
// without influencing global objects. | ||
'var global = window; ' + // window is our new global object | ||
'eval(require("rewire").getImportGlobalsSrc()); ' + | ||
// The module src is wrapped inside a self-executing function. | ||
// This is necessary to separate the module src from the preceding eval(importGlobalsSrc), | ||
// because the module src can be in strict mode. | ||
// In strict mode eval() can only declare vars in the current scope. In this case our setters | ||
// and getters won't work. | ||
// @see https://developer.mozilla.org/en/JavaScript/Strict_mode#Making_eval_and_arguments_simpler | ||
"(function () {" + | ||
// If the module uses strict mode we must ensure that "use strict" stays at the beginning of the function. | ||
(detectStrictMode(src)? ' "use strict"; ': ' ') + | ||
injectionSrc + "\n" + | ||
src; | ||
src + | ||
"})();"; | ||
} | ||
@@ -77,4 +100,2 @@ | ||
b.register(".js", injectRewire); | ||
// Append rewire initialization at the end of the bundle | ||
b.append(browserInit); | ||
@@ -81,0 +102,0 @@ return b; |
@@ -0,4 +1,37 @@ | ||
require("../browser/shims.js"); // some shims for older browsers that are necessary for rewire() | ||
var pathUtil = require("path"), | ||
browserifyRequire = window.browserifyRequire; | ||
getImportGlobalsSrc = require("../getImportGlobalsSrc.js"); | ||
/** | ||
* Clones an object deeply. Used to clone the module-object that is | ||
* stored in the cache. Because browserify doesn't create the module- | ||
* object newly if the module is executed again we can't modify the | ||
* exports object directly. Instead of we have to make an independent copy. | ||
* | ||
* @param {!Object} obj | ||
* @return {Object} | ||
*/ | ||
function clone(obj) { | ||
var target = {}, | ||
value, | ||
key; | ||
for (key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
value = obj[key]; | ||
if (Array.isArray(value)) { | ||
target[key] = value.slice(0); | ||
} else if (typeof value === "object" && value !== null) { | ||
target[key] = clone(value); | ||
} else { | ||
target[key] = value; | ||
} | ||
} | ||
} | ||
return target; | ||
} | ||
// Saves all setters and getters for every module according to its filename | ||
@@ -14,10 +47,12 @@ var registry = {}, | ||
* @param {!String} parentModulePath __filename of the module, that wants to rewire() another module. | ||
* @param {!String} targetPath path to the module that shall be rewired | ||
* @param {!String} path path to the module that shall be rewired | ||
* @param {Boolean=true} cache indicates whether the rewired module should be cached or not | ||
* @return {Object} | ||
*/ | ||
function browserifyRewire(parentModulePath, targetPath, cache) { | ||
function browserifyRewire(parentModulePath, path, cache) { | ||
var originalModule, | ||
rewiredModule = {}, | ||
registeredTargetModule; | ||
absPath, | ||
rewiredExports, | ||
rewiredModule, | ||
registryEntry; | ||
@@ -29,41 +64,39 @@ // Default cache to true | ||
// Make absolute paths | ||
if (targetPath.charAt(0) === ".") { | ||
targetPath = pathUtil.resolve(pathUtil.dirname(parentModulePath), targetPath); | ||
// Normalize path with file extensions | ||
absPath = pathUtil.resolve(parentModulePath, path); | ||
// Retrieve original module from cache | ||
originalModule = require.cache[absPath]; | ||
if (originalModule && cache) { | ||
// Delete the original module from the cache so the next call to browserifyRequre() | ||
// executes the module | ||
delete require.cache[absPath]; | ||
} | ||
// Normalize path with file extensions | ||
targetPath = require.resolve(targetPath); | ||
// Require module to trigger rewire.register(). | ||
// Putting (require) in brackets hides it for browserify. | ||
(require)(absPath); | ||
// Deleting module from cache to trigger execution again | ||
delete browserifyRequire.modules[targetPath]._cached; | ||
// Get registry entry of the target module | ||
registryEntry = registry[absPath]; | ||
originalModule = registryEntry.module; | ||
// 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); | ||
// Make an independent copy of the original module so we can modify the copy | ||
// without influencing the original module. | ||
rewiredModule = clone(originalModule); | ||
rewiredExports = rewiredModule.exports; | ||
// Copy all exported values to our rewired module | ||
for (var key in originalModule) { | ||
if (originalModule.hasOwnProperty(key)) { | ||
rewiredModule[key] = originalModule[key]; | ||
} | ||
} | ||
// Apply setter and getters | ||
rewiredExports.__set__ = registryEntry.setter; | ||
rewiredExports.__get__ = registryEntry.getter; | ||
// If caching is enabled we store the rewiredModule in the cache | ||
if (cache) { | ||
browserifyRequire.modules[targetPath]._cached = rewiredModule; | ||
require.cache[absPath] = 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); | ||
rewiredModules.push(absPath); | ||
return rewiredModule; | ||
return rewiredExports; | ||
} | ||
@@ -78,4 +111,5 @@ | ||
*/ | ||
browserifyRewire.register = function (filename, setter, getter) { | ||
browserifyRewire.register = function (filename, module, setter, getter) { | ||
registry[filename] = { | ||
module: module, | ||
setter: setter, | ||
@@ -90,7 +124,9 @@ getter: getter | ||
browserifyRewire.reset = function () { | ||
var modules = browserifyRequire.modules, | ||
i; | ||
var cache = require.cache, | ||
i, | ||
absPath; | ||
for (i = 0; i < rewiredModules.length; i++) { | ||
delete modules[rewiredModules[i]]._cached; | ||
absPath = rewiredModules[i]; | ||
delete cache[absPath]; | ||
} | ||
@@ -101,2 +137,58 @@ | ||
/** | ||
* Provides a special require-proxy. Every module calls require("rewire").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} dirname the __dirname of the module | ||
* @return {Function} requireProxy | ||
*/ | ||
browserifyRewire.getProxy = function (internalRequire, dirname) { | ||
var rewire = internalRequire("rewire"), | ||
rewireProxyInit = false; | ||
function copyProperties(from, to) { | ||
var key; | ||
for (key in from) { | ||
if (from.hasOwnProperty(key)) { | ||
to[key] = from[key]; | ||
} | ||
} | ||
} | ||
function rewireProxy(path, cache) { | ||
return rewire(dirname, path, cache); | ||
} | ||
function requireProxy(path) { | ||
if (path === "rewire") { | ||
if (rewireProxyInit === false) { | ||
copyProperties(rewire, rewireProxy); // lazy copy | ||
rewireProxyInit = true; | ||
} | ||
return rewireProxy; | ||
} else { | ||
return internalRequire(path); | ||
} | ||
} | ||
copyProperties(internalRequire, requireProxy); | ||
return requireProxy; | ||
}; | ||
/** | ||
* Scans for global vars and returns an evalable string that declares all globals as a var. | ||
* This way a global variable can be overridden by __set__ without changing the global instance. | ||
* It is executed each time again to include global variables that have been added later. | ||
* | ||
* @return {String} | ||
*/ | ||
browserifyRewire.getImportGlobalsSrc = function () { | ||
return getImportGlobalsSrc(['require','module','exports','__dirname','__filename','process']); | ||
}; | ||
module.exports = browserifyRewire; |
@@ -0,1 +1,7 @@ | ||
/*** | ||
* Searches for rewire(); statements and returns all strings that are between the brackets. | ||
* | ||
* @param {!String} src | ||
* @return {Array} | ||
*/ | ||
function getRewireRequires(src) { | ||
@@ -2,0 +8,0 @@ var result = [], |
@@ -10,11 +10,16 @@ /** | ||
*/ | ||
function getImportGlobalsSrc() { | ||
function getImportGlobalsSrc(ignore) { | ||
var key, | ||
value, | ||
src = ""; | ||
src = "", | ||
globalObj = typeof global === "undefined"? window: global; | ||
for (key in global) { | ||
if (global.hasOwnProperty(key) && key !== "global") { | ||
value = global[key]; | ||
src += "var " + key + " = global." + key + "; "; | ||
ignore = ignore || []; | ||
for (key in globalObj) { | ||
if (globalObj.hasOwnProperty === undefined || globalObj.hasOwnProperty(key)) { // in IE8 window.hasOwnProperty is undefined | ||
if (key !== "global" && ignore.indexOf(key) === -1) { | ||
value = globalObj[key]; | ||
src += "var " + key + " = global." + key + "; "; | ||
} | ||
} | ||
@@ -21,0 +26,0 @@ } |
{ | ||
"name" : "rewire", | ||
"version" : "0.3.0", | ||
"version" : "0.3.1", | ||
"description" : "Dependency injection for node.js applications", | ||
@@ -30,3 +30,3 @@ "keywords" : [ | ||
"engines" : { | ||
"node" : "<=0.8.x" | ||
"node" : "<0.9.x" | ||
}, | ||
@@ -36,3 +36,3 @@ "devDependencies": { | ||
"expect.js": "0.1.x", | ||
"browserify": "1.13.x" | ||
"browserify": ">=1.13.5 <1.14.x" | ||
}, | ||
@@ -39,0 +39,0 @@ "scripts" : { |
@@ -15,4 +15,7 @@ rewire | ||
Furthermore rewire comes also with support for [browserify](https://github.com/substack/node-browserify). Thus you can mock your modules in the browser as well. | ||
Furthermore rewire comes also with support for [browserify](https://github.com/substack/node-browserify). You just | ||
have to add rewire as a middleware (see below). | ||
[![Build Status](https://secure.travis-ci.org/jhnns/rewire.png?branch=master)](http://travis-ci.org/jhnns/rewire) | ||
<br /> | ||
@@ -26,3 +29,4 @@ | ||
**For older node versions:**<br /> | ||
rewire is tested with node 0.6.x - 0.7.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 - 0.8.x. I recommend to run the unit tests via `mocha` in the rewire-folder before | ||
using rewire with other node versions. | ||
@@ -32,3 +36,2 @@ **Use with [browserify](https://github.com/substack/node-browserify):**<br /> | ||
```javascript | ||
// debug=true splits the source in seperate files in chrome's developer tools | ||
var b = require("browserify")({debug: true}); | ||
@@ -39,2 +42,4 @@ | ||
After that rewire works exactly as in node. | ||
<br /> | ||
@@ -115,5 +120,5 @@ | ||
// If you want to remove all your rewired modules from the | ||
// If you want to remove all your rewired modules from | ||
// cache just call rewire.reset(). | ||
// Do this before every unit test to ensure a clean testing environment. | ||
// Do this after every single unit test to ensure a clean testing environment. | ||
rewire.reset(); | ||
@@ -120,0 +125,0 @@ ``` |
@@ -10,3 +10,3 @@ var expect = require("expect.js"), | ||
return function expectReferenceError(err) { | ||
expect(err.constructor.name).to.be(ErrConstructor.name); | ||
expect(err.constructor.name === ErrConstructor.name).to.be(true); | ||
}; | ||
@@ -21,2 +21,3 @@ } | ||
moduleFake = { | ||
__filename: "some/file.js", | ||
myNumber: 0, | ||
@@ -30,7 +31,8 @@ myObj: {} | ||
"setObj = function (value) { myObj = value; }; ", | ||
moduleFake | ||
moduleFake, | ||
__filename | ||
); | ||
}); | ||
it("should return the initial value", function () { | ||
expect(moduleFake.__get__("myNumber")).to.be(0); | ||
expect(moduleFake.__get__("myNumber") === 0).to.be(true); | ||
expect(moduleFake.__get__("myObj")).to.eql({}); | ||
@@ -43,4 +45,4 @@ }); | ||
moduleFake.setObj(newObj); | ||
expect(moduleFake.__get__("myNumber")).to.be(2); | ||
expect(moduleFake.__get__("myObj")).to.be(newObj); | ||
expect(moduleFake.__get__("myNumber") === 2).to.be(true); | ||
expect(moduleFake.__get__("myObj") === newObj).to.be(true); | ||
}); | ||
@@ -47,0 +49,0 @@ it("should throw a ReferenceError when getting not existing vars", function () { |
@@ -10,3 +10,3 @@ var expect = require("expect.js"), | ||
return function expectReferenceError(err) { | ||
expect(err.constructor.name).to.be(ErrConstructor.name); | ||
expect(err.constructor.name === ErrConstructor.name).to.be(true); | ||
}; | ||
@@ -39,5 +39,5 @@ } | ||
it("should set the new number when calling with varName, varValue", function () { | ||
expect(moduleFake.getNumber()).to.be(0); | ||
expect(moduleFake.getNumber() === 0).to.be(true); | ||
moduleFake.__set__("myNumber", 2); | ||
expect(moduleFake.getNumber()).to.be(2); | ||
expect(moduleFake.getNumber() === 2).to.be(true); | ||
}); | ||
@@ -49,3 +49,3 @@ it("should set the new object when calling with varName, varValue", function () { | ||
moduleFake.__set__("myObj", newObj); | ||
expect(moduleFake.getObj()).to.be(newObj); | ||
expect(moduleFake.getObj() === newObj).to.be(true); | ||
}); | ||
@@ -55,3 +55,3 @@ it("should set the new number and the new obj when calling with an env-obj", function () { | ||
expect(moduleFake.getNumber()).to.be(0); | ||
expect(moduleFake.getNumber() === 0).to.be(true); | ||
expect(moduleFake.getObj()).to.eql({}); | ||
@@ -62,7 +62,7 @@ moduleFake.__set__({ | ||
}); | ||
expect(moduleFake.getNumber()).to.be(2); | ||
expect(moduleFake.getObj()).to.be(newObj); | ||
expect(moduleFake.getNumber() === 2).to.be(true); | ||
expect(moduleFake.getObj() === newObj).to.be(true); | ||
}); | ||
it("should return undefined", function () { | ||
expect(moduleFake.__set__("myNumber", 4)).to.be(undefined); | ||
expect(moduleFake.__set__("myNumber", 4) === undefined).to.be(true); | ||
}); | ||
@@ -80,5 +80,2 @@ it("should throw a ReferenceError when trying to set non-existing vars", function () { | ||
}); | ||
it("should not clash with vars used within the set method", function () { | ||
}); | ||
it("should throw a TypeError when passing misfitting params", function () { | ||
@@ -106,3 +103,9 @@ expect(function () { | ||
}).to.throwException(expectTypeError); | ||
expect(function () { | ||
moduleFake.__set__({}, true); // misfitting number of params | ||
}).to.throwException(expectTypeError); | ||
expect(function () { | ||
moduleFake.__set__("someVar"); // misfitting number of params | ||
}).to.throwException(expectTypeError); | ||
}); | ||
}); |
@@ -21,3 +21,11 @@ var vm = require("vm"), | ||
afterEach: afterEach, | ||
setTimeout: setTimeout | ||
setTimeout: setTimeout, | ||
clearTimeout: clearTimeout, | ||
setInterval: setInterval, | ||
clearInterval: clearInterval, | ||
parseFloat: parseFloat, | ||
parseInt: parseInt, | ||
encodeURIComponent: function () {}, | ||
decodeURIComponent: function () {}, | ||
document: {} | ||
}, | ||
@@ -31,73 +39,6 @@ console: console | ||
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) { | ||
it("should run all sharedTestCases without exception", function () { | ||
var b = browserify({debug: true}), | ||
middleware = require("rewire").browserify, | ||
browserOutput = __dirname + "/browser/browseroutput.js", | ||
browserOutput = __dirname + "/browserify/bundle.js", | ||
browserBundle, | ||
@@ -107,3 +48,3 @@ vmBundle; | ||
b.use(middleware); | ||
b.require(__dirname + "/testModules/sharedTestCases.js"); | ||
b.addEntry(__dirname + "/testModules/sharedTestCases.js"); | ||
vmBundle = b.bundle(); | ||
@@ -113,18 +54,13 @@ browserBundle = vmBundle; | ||
// Setup for mocha | ||
browserBundle += 'window.onload = function () {' + | ||
'mocha.setup("bdd");' + | ||
'window.browserifyRequire("/test/testModules/sharedTestCases.js");' + | ||
'mocha.run();' + | ||
'};'; | ||
browserBundle = "function enableTests() {" + browserBundle + "}"; | ||
vmBundle += 'window.browserifyRequire("/test/testModules/sharedTestCases.js");'; | ||
/* | ||
vmBundle += 'window.browserifyRequire("/test/testModules/sharedTestCases.js");'; */ | ||
// Output for browser-testing | ||
fs.mkdir(__dirname + "/browser", function onMkDir() { | ||
fs.writeFile(browserOutput, browserBundle, "utf8", done); | ||
fs.writeFileSync(browserOutput, browserBundle, "utf8"); | ||
// This should throw no exception. | ||
runInFakeBrowserContext(vmBundle, browserOutput); | ||
}); | ||
// This should throw no exception. | ||
runInFakeBrowserContext(vmBundle, browserOutput); | ||
}); | ||
}); |
@@ -6,9 +6,9 @@ var expect = require("expect.js"), | ||
it("should detect \"use strict\"; at the beginning of a string and ignore all whitespace before", function () { | ||
expect(detectStrictMode('"use strict";')).to.be(true); | ||
expect(detectStrictMode(' "use strict";')).to.be(true); | ||
expect(detectStrictMode(' \n "use strict";')).to.be(true); | ||
expect(detectStrictMode('"use strict";') === true).to.be(true); | ||
expect(detectStrictMode(' "use strict";') === true).to.be(true); | ||
expect(detectStrictMode(' \n "use strict";') === true).to.be(true); | ||
}); | ||
it("should not detect \"use strict\"; if it occurs in some nested function", function () { | ||
expect(detectStrictMode('function () {"use strict";}')).to.be(false); | ||
expect(detectStrictMode('function () {"use strict";}') === false).to.be(true); | ||
}); | ||
}); |
@@ -22,2 +22,22 @@ var expect = require("expect.js"), | ||
}); | ||
it("should ignore the given variables", function () { | ||
var context = { | ||
global: global | ||
}, | ||
ignore = ["console", "setTimeout"], | ||
src, | ||
actualGlobals, | ||
expectedGlobals = Object.keys(global); | ||
src = getImportGlobalsSrc(ignore); | ||
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); | ||
}); | ||
}); |
@@ -31,17 +31,65 @@ "use strict"; // run code in ES5 strict mode | ||
function checkSomeGlobals() { | ||
if (typeof global === "undefined") { | ||
throw new ReferenceError("global is undefined"); | ||
if (typeof global !== "object") { | ||
throw new ReferenceError("global is not an object"); | ||
} | ||
if (typeof console === "undefined") { | ||
throw new ReferenceError("console is undefined"); | ||
if (typeof console !== "object") { | ||
throw new ReferenceError("console is not an object"); | ||
} | ||
if (typeof __filename === "undefined") { | ||
throw new ReferenceError("__filename is undefined"); | ||
if (typeof require !== "function") { | ||
throw new ReferenceError("require is not a function"); | ||
} | ||
if (typeof __dirname === "undefined") { | ||
throw new ReferenceError("__dirname is undefined"); | ||
if (typeof module !== "object") { | ||
throw new ReferenceError("module is not an object"); | ||
} | ||
if (typeof setTimeout === "undefined") { | ||
throw new ReferenceError("setTimeout is undefined"); | ||
if (typeof exports !== "object") { | ||
throw new ReferenceError("exports is not an object"); | ||
} | ||
if (module.exports !== exports) { | ||
throw new Error("module.exports === exports returns false"); | ||
} | ||
if (typeof __dirname !== "string") { | ||
throw new ReferenceError("__dirname is not a string"); | ||
} | ||
if (typeof __filename !== "string") { | ||
throw new ReferenceError("__filename is not a string"); | ||
} | ||
if (typeof setTimeout !== "function") { | ||
throw new ReferenceError("setTimeout is not a function"); | ||
} | ||
if (typeof clearTimeout !== "function") { | ||
throw new ReferenceError("clearTimeout is not a function"); | ||
} | ||
if (typeof setInterval !== "function") { | ||
throw new ReferenceError("setInterval is not a function"); | ||
} | ||
if (typeof clearInterval !== "function") { | ||
throw new ReferenceError("clearInterval is not a function"); | ||
} | ||
if (typeof Error !== "function") { | ||
throw new ReferenceError("Error is not a function"); | ||
} | ||
if (typeof parseFloat !== "function") { | ||
throw new ReferenceError("parseFloat is not a function"); | ||
} | ||
if (typeof parseInt !== "function") { | ||
throw new ReferenceError("parseInt is not a function"); | ||
} | ||
if (typeof window === "undefined") { | ||
if (typeof process !== "object") { | ||
throw new ReferenceError("process is not an object"); | ||
} | ||
if (typeof Buffer !== "function") { | ||
throw new ReferenceError("Buffer is not a function"); | ||
} | ||
} else { | ||
if (typeof encodeURIComponent !== "function") { | ||
throw new ReferenceError("encodeURIComponent is not a function"); | ||
} | ||
if (typeof decodeURIComponent !== "function") { | ||
throw new ReferenceError("decodeURIComponent is not a function"); | ||
} | ||
if (typeof document !== "object") { | ||
throw new ReferenceError("document is not an object"); | ||
} | ||
} | ||
} | ||
@@ -57,2 +105,10 @@ | ||
function getBuffer() { | ||
return Buffer; | ||
} | ||
function getDocument() { | ||
return document; | ||
} | ||
// different styles of exports in moduleA.js and moduleB.js | ||
@@ -67,2 +123,4 @@ exports.setMyNumber = setMyNumber; | ||
exports.getFilename = getFilename; | ||
exports.getBuffer = getBuffer; | ||
exports.getDocument = getDocument; | ||
exports.someOtherModule = someOtherModule; |
@@ -31,17 +31,65 @@ "use strict"; // run code in ES5 strict mode | ||
function checkSomeGlobals() { | ||
if (typeof global === "undefined") { | ||
throw new ReferenceError("global is undefined"); | ||
if (typeof global !== "object") { | ||
throw new ReferenceError("global is not an object"); | ||
} | ||
if (typeof console === "undefined") { | ||
throw new ReferenceError("console is undefined"); | ||
if (typeof console !== "object") { | ||
throw new ReferenceError("console is not an object"); | ||
} | ||
if (typeof __filename === "undefined") { | ||
throw new ReferenceError("__filename is undefined"); | ||
if (typeof require !== "function") { | ||
throw new ReferenceError("require is not a function"); | ||
} | ||
if (typeof __dirname === "undefined") { | ||
throw new ReferenceError("__dirname is undefined"); | ||
if (typeof module !== "object") { | ||
throw new ReferenceError("module is not an object"); | ||
} | ||
if (typeof setTimeout === "undefined") { | ||
throw new ReferenceError("setTimeout is undefined"); | ||
if (typeof exports !== "object") { | ||
throw new ReferenceError("exports is not an object"); | ||
} | ||
if (module.exports === exports) { | ||
throw new Error("module.exports === exports returns true"); // because we're exporting via module.exports they should not be the same. | ||
} | ||
if (typeof __dirname !== "string") { | ||
throw new ReferenceError("__dirname is not a string"); | ||
} | ||
if (typeof __filename !== "string") { | ||
throw new ReferenceError("__filename is not a string"); | ||
} | ||
if (typeof setTimeout !== "function") { | ||
throw new ReferenceError("setTimeout is not a function"); | ||
} | ||
if (typeof clearTimeout !== "function") { | ||
throw new ReferenceError("clearTimeout is not a function"); | ||
} | ||
if (typeof setInterval !== "function") { | ||
throw new ReferenceError("setInterval is not a function"); | ||
} | ||
if (typeof clearInterval !== "function") { | ||
throw new ReferenceError("clearInterval is not a function"); | ||
} | ||
if (typeof Error !== "function") { | ||
throw new ReferenceError("Error is not a function"); | ||
} | ||
if (typeof parseFloat !== "function") { | ||
throw new ReferenceError("parseFloat is not a function"); | ||
} | ||
if (typeof parseInt !== "function") { | ||
throw new ReferenceError("parseInt is not a function"); | ||
} | ||
if (typeof window === "undefined") { | ||
if (typeof process !== "object") { | ||
throw new ReferenceError("process is not an object"); | ||
} | ||
if (typeof Buffer !== "function") { | ||
throw new ReferenceError("Buffer is not a function"); | ||
} | ||
} else { | ||
if (typeof encodeURIComponent !== "function") { | ||
throw new ReferenceError("encodeURIComponent is not a function"); | ||
} | ||
if (typeof decodeURIComponent !== "function") { | ||
throw new ReferenceError("decodeURIComponent is not a function"); | ||
} | ||
if (typeof document !== "object") { | ||
throw new ReferenceError("document is not an object"); | ||
} | ||
} | ||
} | ||
@@ -57,11 +105,23 @@ | ||
function getBuffer() { | ||
return Buffer; | ||
} | ||
function getDocument() { | ||
return document; | ||
} | ||
// different styles of exports in moduleA.js and moduleB.js | ||
exports.setMyNumber = setMyNumber; | ||
exports.getMyNumber = getMyNumber; | ||
exports.setMyObj = setMyObj; | ||
exports.getMyObj = getMyObj; | ||
exports.readFileSync = readFileSync; | ||
exports.checkSomeGlobals = checkSomeGlobals; | ||
exports.getConsole = getConsole; | ||
exports.getFilename = getFilename; | ||
exports.someOtherModule = someOtherModule; | ||
module.exports = { | ||
setMyNumber: setMyNumber, | ||
getMyNumber: getMyNumber, | ||
setMyObj: setMyObj, | ||
getMyObj: getMyObj, | ||
readFileSync: readFileSync, | ||
checkSomeGlobals: checkSomeGlobals, | ||
getConsole: getConsole, | ||
getFilename: getFilename, | ||
getBuffer: getBuffer, | ||
getDocument: getDocument, | ||
someOtherModule: someOtherModule | ||
}; |
@@ -19,3 +19,3 @@ // Don't run code in ES5 strict mode. | ||
function checkForTypeError(err) { | ||
expect(err.constructor).to.be(TypeError); | ||
expect(err.constructor === TypeError).to.be(true); | ||
} | ||
@@ -30,9 +30,3 @@ | ||
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; | ||
} | ||
} | ||
delete require.cache[modulePath]; | ||
} | ||
@@ -43,9 +37,9 @@ } | ||
describe("rewire " + (typeof window === "undefined"? "(node.js)": "(browser)"), function () { | ||
beforeEach(cleanRequireCache); // ensuring a clean test environment | ||
afterEach(cleanRequireCache); // ensuring a clean test environment | ||
it("should work like require()", function () { | ||
expect(rewire("./moduleA.js")).to.be(require("./moduleA.js")); | ||
expect(rewire("./moduleA.js") === require("./moduleA.js")).to.be(true); | ||
cleanRequireCache(); | ||
expect(rewire("../testModules/moduleA.js")).to.be(require("../testModules/moduleA.js")); | ||
expect(rewire("../testModules/moduleA.js") === require("../testModules/moduleA.js")).to.be(true); | ||
cleanRequireCache(); | ||
expect(rewire("./moduleA.js")).to.be(require("./moduleA.js")); | ||
expect(rewire("./moduleA.js") === require("./moduleA.js")).to.be(true); | ||
}); | ||
@@ -63,8 +57,8 @@ it("should modify the module so it provides a __set__ - function", function () { | ||
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); | ||
expect(require("./someOtherModule.js").__set__ === undefined).to.be(true); | ||
expect(require("./someOtherModule.js").__get__ === undefined).to.be(true); | ||
expect(require("fs").__set__ === undefined).to.be(true); | ||
expect(require("fs").__get__ === undefined).to.be(true); | ||
}); | ||
it("should not influence global objects by default", function () { | ||
it("should not override/influence global objects by default", function () { | ||
// This should throw no exception | ||
@@ -78,7 +72,7 @@ rewire("./moduleA.js").checkSomeGlobals(); | ||
expect(rewiredModuleA.getMyNumber()).to.be(0); | ||
expect(rewiredModuleA.getMyNumber() === 0).to.be(true); | ||
rewiredModuleA.__set__("myNumber", 2); | ||
expect(rewiredModuleA.getMyNumber()).to.be(2); | ||
expect(rewiredModuleA.getMyNumber() === 2).to.be(true); | ||
rewiredModuleA.__set__("myObj", newObj); | ||
expect(rewiredModuleA.getMyObj()).to.be(newObj); | ||
expect(rewiredModuleA.getMyObj() === newObj).to.be(true); | ||
rewiredModuleA.__set__("env", "ENVENV"); | ||
@@ -89,4 +83,4 @@ }); | ||
expect(rewiredModuleA.__get__("myNumber")).to.be(rewiredModuleA.getMyNumber()); | ||
expect(rewiredModuleA.__get__("myObj")).to.be(rewiredModuleA.getMyObj()); | ||
expect(rewiredModuleA.__get__("myNumber") === rewiredModuleA.getMyNumber()).to.be(true); | ||
expect(rewiredModuleA.__get__("myObj") === rewiredModuleA.getMyObj()).to.be(true); | ||
}); | ||
@@ -97,3 +91,3 @@ it("should provide the ability to inject mocks", function (done) { | ||
readFileSync: function (file) { | ||
expect(file).to.be("bla.txt"); | ||
expect(file === "bla.txt").to.be(true); | ||
done(); | ||
@@ -113,3 +107,3 @@ } | ||
someOtherModule = require("./someOtherModule.js"); | ||
expect(someOtherModule.fs).not.to.be(mockedFs); | ||
expect(someOtherModule.fs === mockedFs).to.be(false); | ||
}); | ||
@@ -120,18 +114,47 @@ it("should provide the ability to mock global objects just within the module", function () { | ||
consoleMock = {}, | ||
bufferMock = {}, | ||
documentMock = {}, | ||
newFilename = "myFile.js"; | ||
rewiredModuleA.__set__({ | ||
console: consoleMock | ||
console: consoleMock, | ||
__filename: newFilename | ||
}); | ||
rewiredModuleA.__set__("__filename", newFilename); | ||
rewiredModuleB.__set__({ | ||
console: consoleMock | ||
}); | ||
rewiredModuleB.__set__("__filename", newFilename); | ||
expect(rewiredModuleA.getConsole()).to.be(consoleMock); | ||
expect(rewiredModuleB.getConsole()).to.be(consoleMock); | ||
expect(console).not.to.be(consoleMock); | ||
expect(rewiredModuleA.getFilename()).to.be(newFilename); | ||
expect(rewiredModuleB.getFilename()).to.be(newFilename); | ||
expect(rewiredModuleA.getConsole() === consoleMock).to.be(true); | ||
expect(rewiredModuleB.getConsole() === consoleMock).to.be(false); | ||
expect(console === consoleMock).to.be(false); | ||
expect(rewiredModuleA.getFilename() === newFilename).to.be(true); | ||
expect(rewiredModuleB.getFilename() === newFilename).to.be(false); | ||
expect(console === newFilename).to.be(false); | ||
if (typeof window === "undefined") { | ||
rewiredModuleA.__set__("Buffer", bufferMock); | ||
expect(rewiredModuleA.getBuffer() === bufferMock).to.be(true); | ||
expect(rewiredModuleB.getBuffer() === bufferMock).to.be(false); | ||
expect(Buffer === bufferMock).to.be(false); | ||
} else { | ||
rewiredModuleA.__set__("document", documentMock); | ||
expect(rewiredModuleA.getDocument() === documentMock).to.be(true); | ||
expect(rewiredModuleB.getDocument() === documentMock === false).to.be(true); | ||
expect(document === documentMock === false).to.be(true); | ||
} | ||
}); | ||
it("should be possible to mock global objects that are added on runtime", function () { | ||
var rewiredModule; | ||
if (typeof window === "undefined") { | ||
global.someGlobalVar = "test"; | ||
rewiredModule = rewire("./moduleA.js"); | ||
rewiredModule.__set__("someGlobalVar", "other value"); | ||
expect(global.someGlobalVar === "test").to.be(true); | ||
expect(rewiredModule.__get__("someGlobalVar") === "other value").to.be(true); | ||
delete global.someGlobalVar; | ||
} else { | ||
window.someGlobalVar = "test"; | ||
rewiredModule = rewire("./moduleA.js"); | ||
rewiredModule.__set__("someGlobalVar", "other value"); | ||
expect(window.someGlobalVar === "test").to.be(true); | ||
expect(rewiredModule.__get__("someGlobalVar") === "other value").to.be(true); | ||
delete window.someGlobalVar; | ||
} | ||
}); | ||
it("should cache the rewired module", function () { | ||
@@ -141,21 +164,26 @@ var rewired; | ||
rewired = rewire("./someOtherModule.js"); | ||
expect(require("./moduleA.js").someOtherModule).to.be(rewired); | ||
expect(require("./moduleA.js").someOtherModule === rewired).to.be(true); | ||
cleanRequireCache(); | ||
rewired = rewire("./someOtherModule.js", true); | ||
expect(require("./moduleA.js").someOtherModule).to.be(rewired); | ||
expect(require("./moduleA.js").someOtherModule === rewired).to.be(true); | ||
}); | ||
it("should not cache the rewired module on demand", function () { | ||
var rewired; | ||
var rewired, | ||
someOtherModule = require("./someOtherModule.js"); | ||
someOtherModule.fs = "This has been changed"; | ||
rewired = rewire("./someOtherModule.js", false); | ||
expect(require("./moduleA.js").someOtherModule).not.to.be(rewired); | ||
expect(require("./moduleA.js").someOtherModule === rewired).to.be(false); | ||
expect(require("./moduleA.js").someOtherModule.fs === "This has been changed").to.be(true); | ||
}); | ||
it("should not influence the original node require if nothing has been required within the rewired module", function () { | ||
it("should not influence the original 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 | ||
expect(require("./moduleA.js").__set__ === undefined).to.be(true); // 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")); | ||
expect(rewire("./moduleA.js") === rewire("./moduleA.js")).to.be(false); | ||
}); | ||
it("should preserve the strict mode", function () { | ||
it("should preserve the strict mode (not IE)", function () { | ||
var strictModule = rewire("./strictModule.js"); | ||
@@ -167,2 +195,10 @@ | ||
}); | ||
it("should return a fresh instance of the module", function () { | ||
var someOtherModule = require("./someOtherModule.js"), | ||
rewiredSomeOtherModule; | ||
someOtherModule.fs = "This has been modified"; | ||
rewiredSomeOtherModule = rewire("./someOtherModule.js"); | ||
expect(rewiredSomeOtherModule.fs === "This has been modified").to.be(false); | ||
}); | ||
describe("#reset", function () { | ||
@@ -173,9 +209,9 @@ it("should remove all rewired modules from cache", function () { | ||
expect(require("./moduleA.js")).to.be(rewiredModuleA); | ||
expect(require("./moduleB.js")).to.be(rewiredModuleB); | ||
expect(require("./moduleA.js") === rewiredModuleA).to.be(true); | ||
expect(require("./moduleB.js") === rewiredModuleB).to.be(true); | ||
rewire.reset(); | ||
expect(require("./moduleA.js")).not.to.be(rewiredModuleA); | ||
expect(require("./moduleB.js")).not.to.be(rewiredModuleB); | ||
expect(require("./moduleA.js") === rewiredModuleA).to.be(false); | ||
expect(require("./moduleB.js") === rewiredModuleB).to.be(false); | ||
}); | ||
}); | ||
}); |
"use strict"; // run code in ES5 strict mode | ||
__filename = "/test/testModules/someOtherModule.js"; // unifying filename for the pretty stack trace test | ||
var fs = require("fs"); | ||
exports.fs = fs; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
47
161
16
0
104829
1241
1