6

I am currently using requirejs to manage module js/css dependencies. I'd like to discover the possibilities of having node do this via a centralized config file. So instead of manually doing something like

define([    
'jquery'
'lib/somelib'
'views/someview']

within each module.

I'd have node inject the dependencies ie

require('moduleA').setDeps('jquery','lib/somelib','views/someview')

Anyway, I'm interested in any projects looking at dependency injection for node.

thanks

6
  • Dependency injection is not for dynamic languages. Commented Dec 2, 2011 at 6:39
  • @justin - thanks but I beg to differ. Maybe the term is incorrect, but isn't what I'm talking about dynamic? Commented Dec 2, 2011 at 7:41
  • 1
    No, dynamic languages are that way by nature and don't need DI. The point of DI is to get around that limitation with static typing. Commented Dec 2, 2011 at 7:51
  • "inject require data dynamically from the server" clux.github.com/modul8 Commented Dec 2, 2011 at 10:27
  • The recent post Javascript has a Built-In Dependency Injection Framework is very relevant: caines.ca/blog/programming/… Commented Apr 3, 2013 at 11:11

3 Answers 3

6

I've come up with a solution for dependency injection. It's called injectr, and it uses node's vm library and replaces the default functionality of require when including a file.

So in your tests, instead of require('libToTest'), use injectr('libToTest' { 'libToMock' : myMock });. I wanted to make the interface as straightforward as possible, with no need to alter the code being tested. I think it works quite well.

It's just worth noting that injectr files are relative to the working directory, unlike require which is relative to the current file, but that shouldn't matter because it's only used in tests.

Sign up to request clarification or add additional context in comments.

1 Comment

Nice lib. I made one some time ago :) github.com/lukeschafer/modulemock never really continued development on it
5

I've previously toyed with the idea of providing an alternate require to make a form of dependency injection available in Node.js.

Module code

For example, suppose you have following statements in code.js: fs = require('fs');

console.log(fs.readFileSync('text.txt', 'utf-8'));

If you run this code with node code.js, then it will print out the contents of text.txt.

Injector code

However, suppose you have a test module that wants to abstract away the file system.
Your test file test.js could then look like this:

var origRequire = global.require;
global.require = dependencyLookup;
require('./code.js');

function dependencyLookup (file) {
  switch (file) {
    case 'fs': return { readFileSync: function () { return "test contents"; } };
    default: return origRequire(file);
  }
}

If you now run node test.js, it will print out "test contents", even though it includes code.js.

2 Comments

Does this still work for you? All my relative paths break when I try this approach. Error: Cannot find module './lib/model-store.js' It's as if all modules are trying to load from the base directory of the tests, instead of the file under test.
Since this code uses the regular require eventually, I suspect it is a path error on your side. Could you verify if it still works without the injector code?
2

I've also written a module to accomplish this, it's called rewire. Just use npm install rewire and then:

var rewire = require("rewire"),
    myModule = rewire("./path/to/myModule.js"); // exactly like require()

// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123


// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
    readFile: function (path, encoding, cb) {
        cb(null, "Success!");
    }
});
myModule.readSomethingFromFileSystem(function (err, data) {
    console.log(data); // = Success!
});

I've been inspired by Nathan MacInnes's injectr but used a different approach. I don't use vm to eval the test-module, in fact I use node's own require. This way your module behaves exactly like using require() (except your modifications). Also debugging is fully supported.

2 Comments

Interesting approach. I guess my implementation at github.com/lukeschafer/modulemock is more like injectr
while i find mocking require a common pattern in JS i still struggle with the idea of declaring dependencies with requiring a file vs declaring them in the constructor and resolving them at composition root. i've opened a SO question on this exact topic here: stackoverflow.com/questions/37836813/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.