dissect
exposes private variables within modules allowing developers to write significantly more granular unit tests.
Inspired by rewire.
Supports Node 4+ (might work for other version; don't know, don't care)
Consider the following module to be under test
// index.js
var request = require('request');
var generateAPIEndpoint = slackMethod => `https://slack.com/api/${slackMethod}`;
function makeCall(slackMethod, options, doneCalling) {
const temp = Object.assign({
url: generateAPIEndpoint(slackMethod)
}, options);
return request(temp, doneCalling);
}
module.exports = {
createConversation: makeCall.bind(null, 'conversation.create'),
closeConversation: makeCall.bind(null, 'conversation.close')
};
With dissect
, you can
// test/unit/index.js
// One off require per node process
require('dissect');
// note the `dissect` extension
var index = require('../../index.dissect');
var temp = index.__get('generateAPIEndpoint');
console.log(temp); // [Function]
console.log(temp('dummy')); // "https://slack.com/api/dummy"
index.__set('generateAPIEndpoint', function(slackMethod) {
return `localhost:7651/api/${slackMethod}`
});
index.createConversation(someOptions, console.log); // call now goes to localhost at port 7651
global
is available to the dissected module as one would expect. So the following are possible within the dissected module,
global.hello = 'there' // available throughout the node process
console.log('hello!') // console is available through the global object
process.env = {} // `process.env` is now an empty object everywhere.
You can also "inject" variables into the dissected script's scope
// a.js
module.exports = {
returnNonExistent: function() {
return nonExistent;
}
};
// dissector.js
require('dissect');
var a = require('a.dissect');
a.__set('nonExistent', 3);
console.log(a.returnNonExistent()); // 3
const dissectConfigure = require('dissect');
dissectConfigure({
replaceConstWithVar: <Boolean>, // Should `const` and `let` declarations be changed to `var`? (defaults to false)
clearCache: <Boolean> // Should the dissected module to cached? (defaults to false)
});
const underTest = require('someModule.dissect');
underTest.__get || underTest.__set
underTest.normallyExportedThings;
Variables within IIFE
cannot be exposed.
(function() {
var a = 3; // cannot be accessed
})();
Modules that export primitives will behave slightly differently.
// a.js
modules.exports = 3;
// dissector.js
require('dissect');
var a = require('a.dissect');
a.__get // function
a.__set // function
a.exports // 3
- Dissected modules, similar to normal modules, are cached by default. This can be overridden via the
clearCache
configuration. - Variables declared using
const
andlet
are not exposed via the getter. This can be overcome by changing theconst
andlet
tovar
. This behaviour can be toggled usingreplaceConstWithVar
configuration. __get
only returns values that are declared within the module under dissection.__get('console')
will usually returnundefined
unlessconsole
is defined within the module explicitly.- When using with Node 4,
strict
mode is assumed to turned on. - Please configure before dissecting. Once dissected, the exports will remain the same. (unless
clearCache
is set) - Please dissect only one module at a time (only the module currently under test) Dissecting multiple modules (nested or otherwise) is supported but might result in unexpected behaviour.