npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

deprivation

v3.4.1

Published

testing facilitation, by converting Unit Under Test to a sandboxed version, that exposes module internals without the need to export them.

Downloads

22

Readme

Deprivation

This module facilitate whitebox and blackbox testing (binding it with conventional UT and MT paradigms) of nodejs applications.

We define a module as a folder with implementations.

These are the two main modes of operation of the deprivation module:

  • whitebox unit

    • grants a full access to an object, without the need to export everything in order to test it. useful e.g. in TDD (test small increments without exposing every method), and writing fine-grained tests.
  • blackbox module

    • gives the public access to an object

Both modes enable auto mocking.

Behind the curtains it uses the Node's VM module, and plows the require.cache.

Usage

npm install deprivation

For running a complete suite of tests use the npm test command.

Example implementation (Unit Under Test).

    var glob = require('glob');
    var dep = require('./dep.js');

    var myPrivateFunc = function(param){
        return glob.GlobSync(param);
    };

    var publicFunc = function(param) {
        return myPrivateFunc(param);
    };

    var callAnotherGlob = function() {
        return dep('huhu');
    };

    module.exports.publicFunc = publicFunc;

Basic

An example test file.

    var chamber = require("deprivation").chamber;
    var session = chamber("./implementation.js");

    // uut - Unit Under Test
    var uut = session.whitebox();

    uut.publicFunc("blabla"); // nothing special. Will call private func, which calls the original glob.GlobSync.
    uut.myPrivateFunc("blabla"); // However... note that this func is not exported, but still accessible in a test!
    uut.glob.GlobSync("blabla") // or even this...

Replace dependencies

It's possible to inject any type of a test double: mock, spy, stub, fake, etc., into the UUT.

Example dependency of UUT.

    // dep.js
    module.exports = require('glob').GlobSync;

Right after the module is 'loaded'

  • the UUT code is 'loaded' (= all the require statements are executed in the UUT)
  • the dependencies are replaced after exposition of the UUT
  • replacement in not transitive!
// let's get rid of glob.GlobSync dependency
    uut.glob.GlobSync = function(){};

// all calls execute the dummy function
    uut.publicFunc('blabla');
    uut.myPrivateFunc('blabla');
    uut.glob.GlobSync('blabla');

// ...but not this one!
    uut.callAnotherGlob();

Through an option

Leads to a different result:

  • if the replacement is an object, the require initialization code of the replaced dependancies is not executed
  • if the replacement is a string (as in the require statement), the require initialization code is executed
  • replacement is transitive (it is replaced globally)
    var myGlob = {GlobSync: function() {return './.ssh/id_rsa.priv'}}
    var session = chamber('./implementation.js', {replace:[{'glob': myGlob}]});
    var uut = session.whitebox();

    // all calls return './.ssh/id_rsa.priv'
    uut.glob.GlobSync('something');
    uut.callAnotherGlob('something');

Blackbox, through an option, with more automation

If a function exists, which accepts an object, and returns its test double,

// A jasmine spy-maker example

    var myReplacer = function (obj) {
        Object.keys(obj).forEach(function (item) {
            spyOn(obj, item);
        });
    };

it can be passed on with the replacer option.

    seance = chamber("myModule/impl.js", {replace: ['glob', '../*'], replacer: myReplacer});

In the above example

  • the magical '../*' string means that all implementations outside of myModule folder will be automatically transformed into spies. This omits the node_module folder.
  • due to the above, the glob package is added explicitly, and will be automatically turned into a mock,

'*' replaces all implementations (within the same folder too!)

An example test suite (jasmine/mocha):

    beforeEach(function () {
        sut = seance.blackbox();
        spies = seance.getTestDoubles();
    });

spies above are the spy objects references, stored in a dictionary. This allows to work with objects, that are inaccessible from the module's public interface.

The expectation may be set, using the obtained references.

    it('uses GlobSync', function () {
        sut.arrangeHeapDumps('bleble');
        expect(spies['node_modules/glob/glob.js'].GlobSync).toHaveBeenCalled();
    });

Test doubles are accessed using the path relative to the process current directory. This is the most readable way to specify, which test double object is referenced (the glob package may be used by other sub-packages, in different versions, etc.)

Clone the project from the repository and refer to the test/*.* files for more examples.