Skip to content

lightweight, zero dependency, monkey patching for NodeJS

Notifications You must be signed in to change notification settings

vivekannan/dissect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dissect

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)

Examples

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

Usage

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;

Limitations

IIFE

Variables within IIFE cannot be exposed.

(function() {
    var a = 3; // cannot be accessed
})();

Primitive exports

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

Notes

  1. Dissected modules, similar to normal modules, are cached by default. This can be overridden via the clearCache configuration.
  2. Variables declared using const and let are not exposed via the getter. This can be overcome by changing the const and let to var. This behaviour can be toggled using replaceConstWithVar configuration.
  3. __get only returns values that are declared within the module under dissection. __get('console') will usually return undefined unless console is defined within the module explicitly.
  4. When using with Node 4, strict mode is assumed to turned on.
  5. Please configure before dissecting. Once dissected, the exports will remain the same. (unless clearCache is set)
  6. 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.

About

lightweight, zero dependency, monkey patching for NodeJS

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published