UNPKG

require-inject

Version:

A simple mock injector compatible needing no instrumentation in the libraries being tested

94 lines (77 loc) 2.81 kB
'use strict' var Module = require('module') var path = require('path') var caller = require('caller') try { require('readable-stream') } catch (_) { // ignore error, just doing the require to work around weirdness in readable-stream } 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) { mocks = mocks || {} // Copy the existing cache var originalCache = {} Object.keys(require.cache).forEach(function (name) { originalCache[name] = require.cache[name] }) 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] }) return mocked } function resolve (callerFilename, name) { if (/^[.][.]?\//.test(name)) { name = path.resolve(path.dirname(callerFilename), name) } return require.resolve(name) } 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() var parent = require.cache[toLoadPath] || null // Inject all of our mocks Object.keys(mocks).forEach(function (name) { var namePath = resolve(callerFilename, name) if (mocks[name] == null) { delete require.cache[namePath] } else { var old = require.cache[namePath] var mod = new Module(namePath, null) mod.filename = namePath mod.exports = mocks[name] mod.loaded = true mod.parent = old ? old.parent : parent require.cache[namePath] = mod } }) var toLoadPath = resolve(callerFilename, toLoad) // remove any unmocked version previously loaded delete require.cache[toLoadPath] // load our new version using our mocks return require.cache[callerFilename].require(toLoadPath) }