require-inject
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -0,1 +1,23 @@ | ||
## v1.4.0 (2016-06-03) | ||
Add `requireInject.withEmptyCache` and | ||
`requireInject.installGlobally.andClearCache` to support loading modules | ||
to be injected with an empty cache. This can be useful when your test shares | ||
dependencies with the module to be mocked and you need to mock a transitive | ||
dependency of one of those dependencies. That is: | ||
``` | ||
Test → A → B | ||
ModuleToTest → A → MockedB | ||
``` | ||
If we we didn't clear the cache then `ModuleToTest` would get the already | ||
cached version of `A` and the `MockedB` would never be injected. By clearing the cache | ||
first it means that `ModuleToTest` will get it's own copy of `A` which will then pick | ||
up any mocks we defined. | ||
Previously to achieve this you would need to have provided a mock for `A`, | ||
which, if that isn't what you were testing, could be frustrating busy work. | ||
## v1.3.1 (2016-03-04) | ||
@@ -2,0 +24,0 @@ |
58
index.js
@@ -1,18 +0,38 @@ | ||
"use strict"; | ||
var path = require("path") | ||
var caller = require('caller'); | ||
'use strict' | ||
var path = require('path') | ||
var caller = require('caller') | ||
module.exports = function (toLoad, mocks) { | ||
exports = module.exports = function (toLoad, mocks) { | ||
return requireInject(toLoad, mocks) | ||
} | ||
exports.withEmptyCache = function (toLoad, mocks) { | ||
return requireInject(toLoad, mocks, true) | ||
} | ||
exports.installGlobally = installGlobally | ||
exports.installGlobally.andClearCache = function (toLoad, mocks) { | ||
var callerFilename = getCallerFilename() | ||
Object.keys(require.cache).forEach(function (name) { | ||
if (name !== callerFilename) delete require.cache[name] | ||
}) | ||
return installGlobally(toLoad, mocks) | ||
} | ||
var requireInject = function (toLoad, mocks, withEmptyCache) { | ||
// Copy the existing cache | ||
var originalCache = {} | ||
Object.keys(require.cache).forEach(function(name) { | ||
Object.keys(require.cache).forEach(function (name) { | ||
originalCache[name] = require.cache[name] | ||
}) | ||
var mocked = installGlobally(toLoad, mocks) | ||
var mocked = withEmptyCache | ||
? installGlobally.andClearCache(toLoad, mocks) | ||
: installGlobally(toLoad, mocks) | ||
// restore the cache, we can't just assign originalCache to require.cache as the require | ||
// object is unique to each module, even though require.cache is shared | ||
Object.keys(require.cache).forEach(function(name){ delete require.cache[name] }) | ||
Object.keys(originalCache).forEach(function(name){ require.cache[name] = originalCache[name] }) | ||
Object.keys(require.cache).forEach(function (name) { delete require.cache[name] }) | ||
Object.keys(originalCache).forEach(function (name) { require.cache[name] = originalCache[name] }) | ||
@@ -22,3 +42,3 @@ return mocked | ||
function resolve(callerFilename, name) { | ||
function resolve (callerFilename, name) { | ||
if (/^[.][.]?\//.test(name)) { | ||
@@ -30,12 +50,20 @@ name = path.resolve(path.dirname(callerFilename), name) | ||
var installGlobally = module.exports.installGlobally = function (toLoad, mocks) { | ||
var callerFilename = caller() == module.filename ? caller(2) : caller(); | ||
function getCallerFilename () { | ||
var callerFilename | ||
for (var ii = 1; ii <= 10; ++ii) { | ||
callerFilename = caller(ii) | ||
if (callerFilename !== module.filename) return callerFilename | ||
} | ||
throw new Error("Couldn't find caller that wasn't " + module.filename + ' in most recent 10 stackframes') | ||
} | ||
function installGlobally (toLoad, mocks) { | ||
var callerFilename = getCallerFilename() | ||
// Inject all of our mocks | ||
Object.keys(mocks).forEach(function(name){ | ||
Object.keys(mocks).forEach(function (name) { | ||
var namePath = resolve(callerFilename, name) | ||
if (mocks[name] == null) { | ||
delete require.cache[namePath] | ||
} | ||
else { | ||
} else { | ||
require.cache[namePath] = {exports: mocks[name]} | ||
@@ -50,3 +78,3 @@ } | ||
// load our new version using our mocks | ||
return require.cache[callerFilename].require(toLoadPath); | ||
return require.cache[callerFilename].require(toLoadPath) | ||
} |
{ | ||
"name": "require-inject", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "A simple mock injector compatible needing no instrumentation in the libraries being tested", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "tap test/*.js" | ||
"test": "standard && tap test/*.js" | ||
}, | ||
@@ -23,2 +23,4 @@ "author": "Rebecca Turner <me@re-becca.org> (http://re-becca.org)", | ||
"devDependencies": { | ||
"standard": "^7.1.2", | ||
"tacks": "1.0.11", | ||
"tap": "^2.2.0" | ||
@@ -25,0 +27,0 @@ }, |
@@ -22,5 +22,5 @@ require-inject | ||
var myglobal = requireInject.installGlobally('myglobal', { … }) | ||
### Usage | ||
### Usage in your tests | ||
* **`var mymod = requireInject( module, mocks )`** | ||
@@ -34,3 +34,3 @@ | ||
*mocks* is an object with keys that are the names of the modules you want | ||
*to mock and values of the mock version of the objects. | ||
to mock and values of the mock version of the objects. | ||
@@ -42,6 +42,35 @@ **requireInject** makes it so that when *module* is required, any of its | ||
* **`var mymod = requireInject.withClearCache(module, mocks)`** | ||
As with `requireInject` but your require cache will be cleared before requring | ||
the module to have mocks injected into it. This can be useful when your test shares | ||
dependencies with the module to be mocked and you need to mock a transitive | ||
dependency of one of those dependencies. That is: | ||
``` | ||
Test → A → B | ||
ModuleToTest → A → MockedB | ||
``` | ||
If we we didn't clear the cache then `ModuleToTest` would get the already | ||
cached version of `A` and the `MockedB` would never be injected. By clearing the cache | ||
first it means that `ModuleToTest` will get it's own copy of `A` which will then pick | ||
up any mocks we defined. | ||
Previously to achieve this you would need to have provided a mock for `A`, | ||
which, if that isn't what you were testing, could be frustrating busy work. | ||
* **`var myglobal = requireInject.installGlobally( module, mocks)`** | ||
As with `requireInject`, except that the module and its mocks are left in | ||
the require cache and any future requires will end up using them too. This is | ||
helpful particularly in the case of things that defer loading. | ||
the require cache and any future requires will end up using them too. This | ||
is helpful particularly in the case of things that defer loading (that is, | ||
do async loading). | ||
* **`var myglobal = requireInject.installGlobally.andClearCache(module, mocks)`** | ||
As with `requireInject.installGlobally` but clear the cache first as with | ||
`requireInject.withClearCache`. Because this globally clears the cache it | ||
means that any requires after this point will get fresh copies of their | ||
required modules, even if you required them previously. |
@@ -1,12 +0,40 @@ | ||
"use strict"; | ||
var test = require("tap").test | ||
var requireInject = require("../index") | ||
'use strict' | ||
var test = require('tap').test | ||
var requireInject = require('../index') | ||
var path = require('path') | ||
var Tacks = require('tacks') | ||
var File = Tacks.File | ||
var Dir = Tacks.Dir | ||
var fixturepath = path.resolve(__dirname, 'lib') | ||
var fixture = new Tacks( | ||
Dir({ | ||
'a.js': File( | ||
"'use strict'\n" + | ||
"var b = require('./b')\n" + | ||
'module.exports = function (infile, outfile, cb) {\n' + | ||
' b(infile, outfile, cb)\n' + | ||
'}\n' | ||
), | ||
'b.js': File( | ||
"'use strict'\n" + | ||
"var fs = require('fs')\n" + | ||
'module.exports = function (infile, outfile, cb) {\n' + | ||
' fs.rename(infile, outfile, cb)\n' + | ||
'}\n' | ||
) | ||
}) | ||
) | ||
test("injection leaking at a distance", function(t) { | ||
test('setup', function (t) { | ||
setup() | ||
t.done() | ||
}) | ||
test('injection leaking at a distance', function (t) { | ||
t.plan(2) | ||
var first = requireInject("./lib/a", { | ||
"fs": { | ||
rename: function(infile, outfile, cb) { | ||
var first = requireInject('./lib/a', { | ||
'fs': { | ||
rename: function (infile, outfile, cb) { | ||
cb() | ||
@@ -16,7 +44,19 @@ } | ||
}) | ||
first("in", "out", function (err) { t.notOk(err,"should be able to rename a file") }) | ||
first('in', 'out', function (err) { t.notOk(err, 'should be able to rename a file') }) | ||
var second = require("./lib/a"); | ||
var second = require('./lib/a') | ||
second("in", "out", function (err) { t.ok(err,"shouldn\'t be able to rename now") }) | ||
second('in', 'out', function (err) { t.ok(err, 'shouldn\'t be able to rename now') }) | ||
}) | ||
test('cleanup', function (t) { | ||
cleanup() | ||
t.done() | ||
}) | ||
function setup () { | ||
cleanup() | ||
fixture.create(fixturepath) | ||
} | ||
function cleanup () { | ||
fixture.remove(fixturepath) | ||
} |
@@ -1,11 +0,40 @@ | ||
'use strict'; | ||
var test = require("tap").test | ||
'use strict' | ||
var test = require('tap').test | ||
var requireInject = require('../index') | ||
var path = require('path') | ||
var Tacks = require('tacks') | ||
var File = Tacks.File | ||
var Dir = Tacks.Dir | ||
test("injection leaking at a distance", function(t) { | ||
var fixturepath = path.resolve(__dirname, 'lib') | ||
var fixture = new Tacks( | ||
Dir({ | ||
'b.js': File( | ||
"'use strict'\n" + | ||
"var fs = require('fs')\n" + | ||
'module.exports = function (infile, outfile, cb) {\n' + | ||
' fs.rename(infile, outfile, cb)\n' + | ||
'}\n' | ||
), | ||
'c.js': File( | ||
"'use strict'\n" + | ||
"var b = require('./b')\n" + | ||
'module.exports = function (infile, outfile, cb) {\n' + | ||
' b(infile, outfile, cb)\n' + | ||
'}\n' | ||
) | ||
}) | ||
) | ||
test('setup', function (t) { | ||
setup() | ||
t.done() | ||
}) | ||
test('injection leaking at a distance', function (t) { | ||
t.plan(2) | ||
var first = requireInject("./lib/b", { | ||
"fs": { | ||
rename: function(infile, outfile, cb) { | ||
var first = requireInject('./lib/b', { | ||
'fs': { | ||
rename: function (infile, outfile, cb) { | ||
cb() | ||
@@ -15,7 +44,19 @@ } | ||
}) | ||
first("in", "out", function (err) { t.notOk(err,"should be able to rename a file") }) | ||
first('in', 'out', function (err) { t.notOk(err, 'should be able to rename a file') }) | ||
var second = require("./lib/c"); | ||
var second = require('./lib/c') | ||
second("in", "out", function (err) { t.ok(err,"shouldn\'t be able to rename now") }) | ||
second('in', 'out', function (err) { t.ok(err, 'shouldn\'t be able to rename now') }) | ||
}) | ||
test('cleanup', function (t) { | ||
cleanup() | ||
t.done() | ||
}) | ||
function setup () { | ||
cleanup() | ||
fixture.create(fixturepath) | ||
} | ||
function cleanup () { | ||
fixture.remove(fixturepath) | ||
} |
'use strict' | ||
var path = require('path') | ||
var test = require('tap').test | ||
var Tacks = require('tacks') | ||
var File = Tacks.File | ||
var Dir = Tacks.Dir | ||
var requireInject = require('../index') | ||
var testdir = path.join(__dirname, path.basename(__filename, '.js')) | ||
var adir = path.join(testdir, 'a') | ||
var bdir = path.join(testdir, 'b') | ||
var brelative = './' + path.relative(__dirname, bdir) | ||
var fixture = new Tacks( | ||
Dir({ | ||
'a.js': File( | ||
"'use strict';\n" + | ||
"var b = require('./b');\n" + | ||
'module.exports = function(infile, outfile, cb) {\n' + | ||
' b(infile, outfile, cb);\n' + | ||
'};\n' | ||
), | ||
'b.js': File( | ||
"'use strict';\n" + | ||
"var fs = require('fs');\n" + | ||
'module.exports = function(infile, outfile, cb) {\n' + | ||
' fs.rename(infile, outfile, cb)\n' + | ||
'};\n' | ||
) | ||
}) | ||
) | ||
test('setup', function (t) { | ||
fixture.create(testdir) | ||
t.end() | ||
}) | ||
test('mock with absolute path', function (t) { | ||
t.plan(1) | ||
var a = requireInject('./lib/a', { | ||
[require.resolve('./lib/b')]: function (infile, outfile, cb) { | ||
var a = requireInject(adir, { | ||
[bdir]: function (infile, outfile, cb) { | ||
cb() | ||
@@ -23,4 +55,4 @@ } | ||
var a = requireInject('./lib/a', { | ||
'./lib/b': function (infile, outfile, cb) { | ||
var a = requireInject(adir, { | ||
[brelative]: function (infile, outfile, cb) { | ||
cb() | ||
@@ -34,1 +66,6 @@ } | ||
}) | ||
test('cleanup', function (t) { | ||
fixture.remove(testdir) | ||
t.end() | ||
}) |
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
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
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
15891
369
74
1
3
11
1