Comparing version 2.0.1 to 2.1.0
@@ -1,41 +0,46 @@ | ||
##Changelog | ||
Changelog | ||
--------- | ||
###2.0.1 | ||
### 2.1.0 | ||
- Added revert feature of `__set__` method | ||
- Introduced `__with__` method to revert changes automatically | ||
### 2.0.1 | ||
- Added test coverage tool | ||
- Small README and description changes | ||
###2.0.0 | ||
### 2.0.0 | ||
- Removed client-side bundler extensions. Browserify is not supported anymore. Webpack support has been extracted | ||
into separate repository https://github.com/jhnns/rewire-webpack | ||
###1.1.3 | ||
### 1.1.3 | ||
- Removed IDE stuff from npm package | ||
###1.1.2 | ||
### 1.1.2 | ||
- Added deprecation warning for client-side bundlers | ||
- Updated package.json for node v0.10 | ||
###1.1.1 | ||
### 1.1.1 | ||
- Fixed bug with modules that had a comment on the last line | ||
###1.1.0 | ||
### 1.1.0 | ||
- Added Coffee-Script support | ||
- Removed Makefile: Use `npm test` instead. | ||
###1.0.4 | ||
### 1.0.4 | ||
- Improved client-side rewire() with webpack | ||
###1.0.3 | ||
### 1.0.3 | ||
- Fixed error with client-side bundlers when a module was ending with a comment | ||
###1.0.2 | ||
### 1.0.2 | ||
- Improved strict mode detection | ||
###1.0.1 | ||
### 1.0.1 | ||
- Fixed crash when a global module has been used in the browser | ||
###1.0.0 | ||
### 1.0.0 | ||
- Removed caching functionality. Now rewire doesn't modify `require.cache` at all | ||
- Added support for [webpack](https://github.com/webpack/webpack)-bundler | ||
- Moved browserify-middleware from `rewire.browserify` to `rewire.bundlers.browserify` | ||
- Reached stable state :) | ||
- Reached stable state :) |
@@ -8,7 +8,5 @@ /** | ||
* | ||
* @param {!String|!Object} varName name of the variable to set | ||
* @param {String|Object} varName name of the variable to set | ||
* @param {String} varValue new value | ||
* @throws {TypeError} | ||
* @throws {ReferenceError} When the variable is unknown | ||
* @return {*} | ||
* @return {Function} | ||
*/ | ||
@@ -19,2 +17,3 @@ function __set__() { | ||
arguments.src = ""; | ||
arguments.snapshot = {}; | ||
@@ -30,2 +29,3 @@ if (typeof arguments[0] === "object" && arguments.length === 1) { | ||
arguments.src += arguments.varName + " = arguments.env." + arguments.varName + "; "; | ||
arguments.snapshot[arguments.varName] = eval(arguments.varName); | ||
} | ||
@@ -38,2 +38,3 @@ } | ||
arguments.src = arguments.varName + " = arguments.varValue;"; | ||
arguments.snapshot[arguments.varName] = eval(arguments.varName); | ||
} else { | ||
@@ -44,4 +45,8 @@ throw new TypeError("__set__ expects an environment object or a non-empty string as a variable name"); | ||
eval(arguments.src); | ||
return function (snapshot) { | ||
module.exports.__set__(snapshot); | ||
}.bind(null, arguments.snapshot); | ||
} | ||
module.exports = __set__; | ||
module.exports = __set__; |
var Module = require("module"), | ||
fs = require("fs"), | ||
__get__ = require("./__get__.js"), | ||
__set__ = require("./__set__.js"), | ||
__set__ = require ("./__set__.js"), | ||
__with__ = require("./__with__.js"), | ||
getImportGlobalsSrc = require("./getImportGlobalsSrc.js"), | ||
@@ -10,3 +11,4 @@ detectStrictMode = require("./detectStrictMode.js"), | ||
var __get__Src = __get__.toString(), | ||
__set__Src = __set__.toString(); | ||
__set__Src = __set__.toString(), | ||
__with_Src = __with__.toString(); | ||
@@ -48,2 +50,3 @@ /** | ||
appendix += "module.exports.__get__ = " + __get__Src + "; "; | ||
appendix += "module.exports.__with__ = " + __with_Src + "; "; | ||
@@ -63,2 +66,2 @@ // Check if the module uses the strict mode. | ||
module.exports = internalRewire; | ||
module.exports = internalRewire; |
{ | ||
"name" : "rewire", | ||
"version" : "2.0.1", | ||
"version" : "2.1.0", | ||
"description" : "Easy dependency injection for node.js unit testing", | ||
@@ -5,0 +5,0 @@ "keywords" : [ |
152
README.md
@@ -5,2 +5,7 @@ rewire | ||
[![Build Status](https://travis-ci.org/jhnns/rewire.svg?branch=master)](http://travis-ci.org/jhnns/rewire) | ||
[![Dependency Status](https://david-dm.org/jhnns/rewire.svg)](https://david-dm.org/jhnns/rewire) | ||
[![Coverage Status](https://img.shields.io/coveralls/jhnns/rewire.svg)](https://coveralls.io/r/jhnns/rewire) | ||
[![Gittip Donate Button](http://img.shields.io/gittip/peerigon.svg)](https://www.gittip.com/peerigon/) | ||
rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may | ||
@@ -21,16 +26,7 @@ | ||
[![Build Status](https://travis-ci.org/jhnns/rewire.svg?branch=master)](http://travis-ci.org/jhnns/rewire) | ||
[![Dependency Status](https://david-dm.org/jhnns/rewire.svg)](https://david-dm.org/jhnns/rewire) | ||
[![Coverage Status](https://img.shields.io/coveralls/jhnns/rewire.svg)](https://coveralls.io/r/jhnns/rewire) | ||
[![npm status](https://nodei.co/npm/rewire.svg?downloads=true&stars=true)](https://npmjs.org/package/rewire) | ||
<br /> | ||
Installation | ||
------------ | ||
`npm install rewire` | ||
<br /> | ||
Examples | ||
Introduction | ||
-------- | ||
@@ -40,15 +36,9 @@ | ||
`lib/myModule.js` | ||
```javascript | ||
// lib/myModule.js | ||
// With rewire you can change all these variables | ||
var fs = require("fs"), | ||
http = require("http"), | ||
someOtherVar = "hi", | ||
myPrivateVar = 1; | ||
path = "/somewhere/on/the/disk"; | ||
function readSomethingFromFileSystem(cb) { | ||
// But no scoped variables | ||
var path = "/somewhere/on/the/disk"; | ||
console.log("Reading from file system ..."); | ||
@@ -63,35 +53,44 @@ fs.readFile(path, "utf8", cb); | ||
`test/myModule.test.js` | ||
```javascript | ||
// test/myModule.test.js | ||
var rewire = require("rewire"); | ||
// rewire acts exactly like require. | ||
var myModule = rewire("../lib/myModule.js"); | ||
``` | ||
// Just with one difference: | ||
// Your module will now export a special setter and getter for private variables. | ||
myModule.__set__("myPrivateVar", 123); | ||
myModule.__get__("myPrivateVar"); // = 123 | ||
rewire acts exactly like require. Just with one difference: Your module will now export a special setter and getter for private variables. | ||
// This allows you to mock almost everything within the module e.g. the fs-module. | ||
// Just pass the variable name as first parameter and your mock as second. | ||
myModule.__set__("fs", { | ||
```javascript | ||
myModule.__set__("path", "/dev/null"); | ||
myModule.__get__("path"); // = '/dev/null' | ||
``` | ||
This allows you to mock everything in the top-level scope of the module, like the fs module for example. Just pass the variable name as first parameter and your mock as second. | ||
```javascript | ||
var fsMock = { | ||
readFile: function (path, encoding, cb) { | ||
expect(path).to.equal("/somewhere/on/the/disk"); | ||
cb(null, "Success!"); | ||
} | ||
}); | ||
}; | ||
myModule.__set__("fs", fsMock); | ||
myModule.readSomethingFromFileSystem(function (err, data) { | ||
console.log(data); // = Success! | ||
}); | ||
``` | ||
// You can set different variables with one call. | ||
You can also set multiple variables with one call. | ||
```javascript | ||
myModule.__set__({ | ||
fs: fsMock, | ||
http: httpMock, | ||
someOtherVar: "hello" | ||
path: "/dev/null" | ||
}); | ||
``` | ||
// 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. | ||
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 | ||
myModule.__set__({ | ||
@@ -105,36 +104,81 @@ console: { | ||
}); | ||
``` | ||
// But be careful, if you do something like this you'll change your global | ||
// console instance. | ||
myModule.__set__("console.log", function () { /* be quiet */ }); | ||
`__set__` returns a function which reverts the changes introduced by this particular `__set__` call | ||
// There is another difference to require: | ||
// Every call of rewire() returns a new instance. | ||
```javascript | ||
var revert = myModule.__set__("port", 3000); | ||
// port is now 3000 | ||
revert(); | ||
// port is now the previous value | ||
``` | ||
For your convenience you can also use the `__with__` method which reverts the given changes after it finished. | ||
```javascript | ||
myModule.__with__({ | ||
port: 3000 | ||
})(function () { | ||
// within this function port is 3000 | ||
}); | ||
// now port is the previous value again | ||
``` | ||
The `__with__` method is also aware of promises. If a thenable is returned all changes stay until the promise has either been resolved or rejected. | ||
```javascript | ||
myModule.__with__({ | ||
port: 3000 | ||
})(function () { | ||
return new Promise(...); | ||
}).then(function () { | ||
// now port is the previous value again | ||
}); | ||
// port is still 3000 here because the promise hasn't been resolved yet | ||
``` | ||
### Caveats | ||
**Difference to require()**<br> | ||
Every call of rewire() executes the module again and returns a fresh instance. | ||
```javascript | ||
rewire("./myModule.js") === rewire("./myModule.js"); // = false | ||
``` | ||
This can especially be a problem if the module is not idempotent [like mongoose models](https://github.com/jhnns/rewire/issues/27). | ||
**Changing globals**<br> | ||
Be careful, if you do something like this you'll change your global console instance. | ||
```javascript | ||
myModule.__set__("console.log", function () { /* be quiet */ }); | ||
``` | ||
<br /> | ||
##API | ||
API | ||
------ | ||
###rewire(filename): rewiredModule | ||
### rewire(filename: String): rewiredModule | ||
- *filename*: <br/> | ||
Path to the module that shall be rewired. Use it exactly like require(). | ||
Returns a rewired version of the module found at `filename`. Use `rewire()` exactly like `require()`. | ||
###rewiredModule.__set__(name, value) | ||
### rewiredModule.__set__(name: String, value: *): Function | ||
- *name*: <br/> | ||
Name of the variable to set. The variable should be global or defined with `var` in the top-leve scope of the module. | ||
- *value*: <br/> | ||
The value to set. | ||
Sets the internal variable `name` to the given `value`. Returns a function which can be called to revert the change. | ||
###rewiredModule.__set__(env) | ||
- *env*: <br/> | ||
Takes all keys as variable names and sets the values respectively. | ||
### rewiredModule.__set__(obj: Object): Function | ||
###rewiredModule.__get__(name): value | ||
Takes all enumerable keys of `obj` as variable names and sets the values respectively. Returns a function which can be called to revert the change. | ||
Returns the private variable. | ||
### rewiredModule.__get__(name: String): * | ||
Returns the private variable with the given `name`. | ||
### rewiredModule.__with__(obj: Object): Function<callback: Function> | ||
Returns a function which - when being called - sets `obj`, executes the given `callback` and reverts `obj`. If `callback` returns a promise, `obj` is only reverted after the promise has been resolved or rejected. For your convenience the returned function passes the received promise through. | ||
<br /> | ||
@@ -141,0 +185,0 @@ |
@@ -5,3 +5,2 @@ var expect = require("expect.js"), | ||
expectReferenceError = expectError(ReferenceError), | ||
expectTypeError = expectError(TypeError); | ||
@@ -16,6 +15,10 @@ | ||
describe("__set__", function () { | ||
var moduleFake; | ||
var moduleFake, | ||
undo; | ||
beforeEach(function () { | ||
moduleFake = { | ||
module: { | ||
exports: {} | ||
}, | ||
myValue: 0, // copy by value | ||
@@ -26,3 +29,4 @@ myReference: {} // copy by reference | ||
vm.runInNewContext( | ||
"__set__ = " + __set__.toString() + "; " + | ||
//__set__ requires __set__ to be present on module.exports | ||
"__set__ = module.exports.__set__ = " + __set__.toString() + "; " + | ||
"getValue = function () { return myValue; }; " + | ||
@@ -75,5 +79,28 @@ "getReference = function () { return myReference; }; ", | ||
}); | ||
it("should return undefined", function () { | ||
expect(moduleFake.__set__("myValue", 4)).to.be(undefined); | ||
it("should return a function that when invoked reverts to the values before set was called", function () { | ||
undo = moduleFake.__set__("myValue", 4); | ||
expect(undo).to.be.a("function"); | ||
expect(moduleFake.getValue()).to.be(4); | ||
undo(); | ||
expect(moduleFake.getValue()).to.be(0); | ||
}); | ||
it("should be able to revert when calling with an env-obj", function () { | ||
var newObj = { hello: "hello" }; | ||
expect(moduleFake.getValue()).to.be(0); | ||
expect(moduleFake.getReference()).to.eql({}); | ||
undo = moduleFake.__set__({ | ||
myValue: 2, | ||
myReference: newObj | ||
}); | ||
expect(moduleFake.getValue()).to.be(2); | ||
expect(moduleFake.getReference()).to.be(newObj); | ||
undo(); | ||
expect(moduleFake.getValue()).to.be(0); | ||
expect(moduleFake.getReference()).to.eql({}); | ||
}); | ||
it("should throw a TypeError when passing misfitting params", function () { | ||
@@ -80,0 +107,0 @@ expect(function () { |
@@ -5,4 +5,12 @@ // Don't run code in ES5 strict mode. | ||
// These shared test cases are used to check if the provided implementation of rewire is compatible | ||
// with the original rewire. Since you can use rewire with client-side bundlers like webpack we need | ||
// to test the implementation there again. | ||
// @see https://github.com/jhnns/rewire-webpack | ||
var expect = require("expect.js"), | ||
rewire = require("rewire"); | ||
rewire = require("rewire"), | ||
__set__Src = require("../../lib/__set__.js").toString(), | ||
__get__Src = require("../../lib/__get__.js").toString(), | ||
__with__Src = require("../../lib/__with__.js").toString(); | ||
@@ -14,2 +22,3 @@ function checkForTypeError(err) { | ||
describe("rewire " + (typeof testEnv === "undefined"? "(node)": "(" + testEnv + ")"), function () { | ||
it("should work like require()", function () { | ||
@@ -21,2 +30,3 @@ rewire("./moduleA.js").getFilename(); | ||
}); | ||
it("should return a fresh instance of the module", function () { | ||
@@ -30,2 +40,3 @@ var someOtherModule = require("./someOtherModule.js"), | ||
}); | ||
it("should not cache the rewired module", function () { | ||
@@ -43,10 +54,21 @@ var rewired, | ||
}); | ||
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); | ||
// By comparing the src we can ensure that the provided __set__ function is our tested implementation | ||
it("should modify the module so it provides the __set__ - function", function () { | ||
expect(rewire("./moduleA.js").__set__.toString()).to.be(__set__Src); | ||
expect(rewire("./moduleB.js").__set__.toString()).to.be(__set__Src); | ||
}); | ||
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); | ||
// By comparing the src we can ensure that the provided __set__ function is our tested implementation | ||
it("should modify the module so it provides the __get__ - function", function () { | ||
expect(rewire("./moduleA.js").__get__.toString()).to.be(__get__Src); | ||
expect(rewire("./moduleB.js").__get__.toString()).to.be(__get__Src); | ||
}); | ||
// By comparing the src we can ensure that the provided __set__ function is our tested implementation | ||
it("should modify the module so it provides the __with__ - function", function () { | ||
expect(rewire("./moduleA.js").__with__.toString()).to.be(__with__Src); | ||
expect(rewire("./moduleB.js").__with__.toString()).to.be(__with__Src); | ||
}); | ||
it("should not influence other modules", function () { | ||
@@ -57,3 +79,5 @@ rewire("./moduleA.js"); | ||
expect(require("./someOtherModule.js").__get__).to.be(undefined); | ||
expect(require("./someOtherModule.js").__with__).to.be(undefined); | ||
}); | ||
it("should not override/influence global objects by default", function () { | ||
@@ -64,3 +88,6 @@ // This should throw no exception | ||
}); | ||
it("should provide the ability to set private vars", function () { | ||
// This is just an integration test for the __set__ method | ||
// You can find a full test for __set__ under /test/__set__.test.js | ||
it("should provide a working __set__ method", function () { | ||
var rewiredModuleA = rewire("./moduleA.js"), | ||
@@ -76,3 +103,6 @@ newObj = {}; | ||
}); | ||
it("should provide the ability to get private vars", function () { | ||
// This is just an integration test for the __get__ method | ||
// You can find a full test for __get__ under /test/__get__.test.js | ||
it("should provide a working __get__ method", function () { | ||
var rewiredModuleA = rewire("./moduleA.js"); | ||
@@ -83,2 +113,24 @@ | ||
}); | ||
// This is just an integration test for the __with__ method | ||
// You can find a full test for __with__ under /test/__with__.test.js | ||
it("should provide a working __with__ method", function () { | ||
var rewiredModuleA = rewire("./moduleA.js"), | ||
newObj = {}; | ||
expect(rewiredModuleA.getMyNumber()).to.be(0); | ||
expect(rewiredModuleA.getMyObj()).to.not.be(newObj); | ||
rewiredModuleA.__with__({ | ||
myNumber: 2, | ||
myObj: newObj | ||
})(function () { | ||
expect(rewiredModuleA.getMyNumber()).to.be(2); | ||
expect(rewiredModuleA.getMyObj()).to.be(newObj); | ||
}); | ||
expect(rewiredModuleA.getMyNumber()).to.be(0); | ||
expect(rewiredModuleA.getMyObj()).to.not.be(newObj); | ||
}); | ||
it("should provide the ability to inject mocks", function (done) { | ||
@@ -96,2 +148,3 @@ var rewiredModuleA = rewire("./moduleA.js"), | ||
}); | ||
it("should not influence other modules when injecting mocks", function () { | ||
@@ -106,2 +159,3 @@ var rewiredModuleA = rewire("./moduleA.js"), | ||
}); | ||
it("should provide the ability to mock global objects just within the module", function () { | ||
@@ -137,2 +191,3 @@ var rewiredModuleA = rewire("./moduleA.js"), | ||
}); | ||
it("should be possible to mock global objects that are added on runtime", function () { | ||
@@ -159,2 +214,3 @@ var rewiredModule; | ||
}); | ||
it("should not be a problem to have a comment on file end", function () { | ||
@@ -166,2 +222,3 @@ var rewired = rewire("./emptyModule.js"); | ||
}); | ||
it("should not influence the original require if nothing has been required within the rewired module", function () { | ||
@@ -171,5 +228,7 @@ rewire("./emptyModule.js"); // nothing happens here because emptyModule doesn't require anything | ||
}); | ||
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 () { | ||
@@ -182,2 +241,3 @@ var strictModule = rewire("./strictModule.js"); | ||
}); | ||
it("should not modify line numbers in stack traces", function () { | ||
@@ -194,2 +254,3 @@ var throwError = rewire("./throwError.js"); | ||
}); | ||
it("should throw a TypeError if the path is not a string", function () { | ||
@@ -200,2 +261,3 @@ expect(function () { | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
59785
33
1168
194
0
9