Automatically generate encoded modules in node.js

I am moving my JavaScript test code from Jest to Mocha. One of the nice things about Jest is that it automatically generates stubs for your modules. These stubs implement the same API as the originals, but all of their functions return undefined

. The exported classes are also shaded, i.e. They have all the same methods as the original, but return undefined:

// mymodule.js
var MyClass = function() { this.foo = 42; };
MyClass.prototype.getFoo = function() { return this.foo; };
module.exports = {
  myclass: MyClass,
  myfunction: function() { return 42; }
};

      

// __tests__/mymodule-test.js
var mm = require('../mymodule');  // Jest auto-mocks this module.

describe('test', function() {
  it('functions and constructors are mocked', function() {
    expect(mm.myfunction()).toEqual(undefined);  // function is stubbed
    var mc = new mm.myclass();
    expect(mc.getFoo()).toEqual(undefined);  // fn on prototype is stubbed.
  });
});

      

For various reasons I am switching to MochaJS, but I would like to keep this behavior. I can stub modules using proxyquire. But I need to identify the butts myself.

I need a function that takes a Node module and returns something like a presumptuous version of a Jest module. The Jest code for this is in moduleMocker.js . I wrote my own code to do this (see below). But this is quite complicated and not like the code I have to write.

Is there a standard library for this?

Here's what I wrote:

// stubber.js
var U = require('underscore');

function replaceFunctionsWithStubs(rootObj) {
  var replacedObjs = [];  // array of [original, replacement] pairs.

  function previousReplacement(obj) {
    for (var i = 0; i < replacedObjs.length; i++) {
      if (replacedObjs[i][0] == obj) {
        return replacedObjs[i][1];
      }
    }
    return null;
  }

  function replacer(obj) {
    var t = typeof(obj);
    if (t != 'function' && t != 'object') {
      // Simple data.
      return obj;
    }

    // Return previous mock to break circular references.
    var prevRep = previousReplacement(obj);
    if (prevRep) return prevRep;

    if (t == 'function') {
      var f = function() {};
      replacedObjs.push([obj, f]);
      if (!U.isEmpty(obj.prototype)) {
        // This might actually be a class. Need to stub its prototype, too.
        var newPrototype = replacer(obj.prototype);
        for (var k in newPrototype) {
          f.prototype[k] = newPrototype[k];
        }
      }

      // Stub any properties the function might have.
      for (var k in obj) {
        f[k] = replacer(obj[k]);
      }
      return f;
    } else if (typeof(obj) == 'object') {
      // TODO: Do I need to handle arrays differently?
      var newObj = {};
      replacedObjs.push([obj, newObj]);

      for (var k in obj) {
        newObj[k] = replacer(obj[k]);
      }
      return newObj;
    } else {
      return obj;  // string, number, null, undefined, ...
    }
  }

  return replacer(rootObj);
}

module.exports = function(m) {
  return replaceFunctionsWithStubs(m);
};

      

+3


source to share





All Articles