nodejs override a function in a module - node.js

I am trying to test a function in a module. This function ( I will refer to it as function_a ) calls a different function ( function_b ) within the same file. So this module looks like this:
//the module file
module.exports.function_a = function (){
//does stuff
function_b()
};
module.exports.function_b = function_b = function () {
//more stuff
}
I need to test function_a with a specific result from function_b.
I would like to override function_b from my test file, then call function_a from my test file, resulting in function_a calling this override function instead of function_b.
Just a note, I have tried and succeeded in overriding functions from separate modules, like this question, but that is not what I am interested in.
I have tried the code below, and as far as I know, doesn't work. It does illustrates what I am going for, though.
//test file
that_module = require("that module")
that_module.function_b = function () { ...override ... }
that_module.function_a() //now uses the override function
Is there a correct way to do this?

From outside a module's code, you can only modify that module's exports object. You can't "reach into" the module and change the value of function_b within the module code. However, you can (and did, in your final example) change the value of exports.function_b.
If you change function_a to call exports.function_b instead of function_b, your external change to the module will happen as expected.

You can actually use the package rewire. It allows you to get and set whatever was declared in the module
foo.js
const _secretPrefix = 'super secret ';
function secretMessage() {
return _secretPrefix + _message();
}
function _message() {
return 'hello';
}
foo.test.js
const rewire = require('rewire');
// Note that the path is relative to `foo.test.js`
const fooRewired = rewire('path_to_foo');
// Outputs 'super secret hello'
fooRewired.secretMessage();
fooRewired.__set__('_message', () => 'ciao')
// Outputs 'super secret ciao'
fooRewired.secretMessage();

Related

Extend module with global configuration without breaking current usages

I want to extend a current Node.js module with some global config setting being configured once without breaking current usages of this module.
This is the signature of the module:
const myFunction = function(someOptions) { ... };
module.exports = myFunction;
Usage is
const myFunction = require('myfunction');
const result = myFunction(options);
Now I want to set some options on application startup to be used by the module myfunction whenever being required without breaking current usages of the module myfunction.
If possible, I want to avoid using Node.js global.
Functions in JavaScript are just objects, so you can give them properties. This is a little hacky, but it could certainly work for you:
// greeter.js
function sayHello() {
const message = sayHello.message || "Hi";
console.log(message);
}
module.exports = sayHello;
You can now set the config of this function globally as follows:
const sayHello = require("./greeter.js");
sayHello.message = "S'up dawg";
Any subsequent calls to sayHello() after the code above is executed will use the overridden message. This works because calls to require() are cached, so each time you require(./greeter.js); you're getting back exactly the same function object.

Best way to invoke code inside a module in nodejs

From a performance perspective, is there any difference between invoking code by wrapping it in a function and then exporting it:
function doSomething () {
// doing something here
}
module.exports = doSomething();
And just requiring it without any exports? like this:
myModule.js
// Code doing something
file that requires the module:
var doSomething = require('./myModule');
And if the purpose of the code inside the module is to run just once, do I need to store it in a variable?
If you don't need the return value of that function, then you don't have to store it in a variable.
The difference with:
function doSomething () {
// doing something here
}
module.exports = doSomething();
and using:
var x = require('module');
var y = require('module');
vs.
function doSomething () {
// doing something here
}
module.exports = doSomething;
and using:
var x = require('module')();
var y = require('module')();
is that in the first case, the function will be run only once, while in the second case the function will be run twice.
The difference is that if you just include it without module.exports, then the code will execute immediately but be private to the module. You can only access the data if you export it somehow, with module.exports. It can be either a function or a Javascript Object. Essentially, you can view everything within the module as being completely hidden from everything else in your application.
The only shortcut that I know of is for JSON files. If you look here: Module.exports vs plain json for config files, you can see that you can require('file.json') and it will replace the contents of the json file with a Javascript object that you can then use in your application.

Node.js inherit local variables

I have a variable in my server.js, lets call it 'a'. When I require a module, it doesn't have access to the variable a. For example:
server.js
myModule = require('./myModule.js');
var a = 'Hello!'
myModule.say();
myModule.js
exports.say = function () {
console.log(a);
}
How can I make it so myModule.js can access the variables in server.js without having function arguments?
server.js:
myModule = require('./myModule.js');
global.a = 'Hello!'
myModule.say();
myModule.js:
exports.say = function () {
console.log(global.a);
}
However, please keep in mind globals are usually discouraged in Node.js (and JavaScript in general). Isn't the point of a module to encapsulate certain functionality? If so, it shouldn't depend on outside variables existing or being defined.
Ideally, you want to pass in the required information into the module via some sort of initialization function or configuration parameters.

Namespaces in node.js with require

I am playing around and learning about vows with a personal project. This is a small client side library, with testing done in vows. Therefore, I must build and test a file that is written like this:
(function(exports) {
var module = export.module = { "version":"0.0.1" };
//more stuff
})(this);
In my testing (based off of science.js, d3, etc.) requires that module like so:
require("../module");
I continued to get a "module not defined error" when trying to run the tests, so I went to a repl and ran:
require("../module")
and it returned:
{ module: { version: "0.0.1" } }
I realize I could do something like:
var module = require("../module").module;
but feel like I am creating a problem by doing it that way, especially since the libraries that I based this project on are doing it in the format I described.
I would like for my project to behave similar to those which I based it off of, where:
require("../module");
creates a variable in this namespace:
module.version; //is valid.
I have seen this in a variety of libraries, and I am following the format and thought process to the T but believe I might be missing something about require behavior I don't know about.
There is no problem creating it this way. Modules define what they return in the module.exports object. By the way, you don't actually need self executing functions (SEF), there is no global leakage like in browsers :-)
Examples
module1.js:
module.exports = {
module: { 'version': '0.1.1' }
};
main.js:
var module1 = require( './module1.js' );
// module1 has what is exported in module1.js
Once you've understood how this works, you can easily export the version number right away if you want to:
module1.js:
module.exports = '0.1.1';
main.js:
var module1 = require( './module1.js' );
console.log( module1 === '0.1.1' ); // true
Or if you want some logic, you can easily extend your module1.js file like this:
module.exports = ( function() {
// some code
return version;
} () ); // note the self executing part :-)
// since it's self executed, the exported part
// is what's returned in the SEF
Or, as many modules do, if you want to export some utility functions (and keep others "private"), you could do it like this:
module.exports = {
func1: function() {
return someFunc();
},
func2: function() {},
prop: '1.0.0'
};
// This function is local to this file, it's not exported
function someFunc() {
}
So, in main.js:
var module1 = require( './module1.js' );
module1.func1(); // works
module1.func2(); // works
module1.prop; // "1.0.0"
module1.someFunc(); // Reference error, the function doesn't exist
Your special case
About your special case, I wouldn't recommend doing it like they're doing.
If you look here: https://github.com/jasondavies/science.js/blob/master/science.v1.js
You see that they're not using the var keyword. So, they're creating a global variable.
This is why they can access it once they require the module defining the global variable.
And by the way, the exports argument is useless in their case. It's even misleading, since it actually is the global object (equivalent of window in browsers), not the module.exports object (this in functions is the global object, it'd be undefined if strict mode were enabled).
Conclusion
Don't do it like they're doing, it's a bad idea. Global variables are a bad idea, it's better to use node's philosophy, and to store the required module in a variable that you reuse.
If you want to have an object that you can use in client side and test in node.js, here is a way:
yourModule.js:
// Use either node's export or the global object in browsers
var global = module ? module.exports : window.yourModule;
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( global ) );
Which you can shorten to this in order to avoid creating the global variable:
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( module ? module.exports : window.yourModule ) );
This way, you can use it like this on the client-side:
yourModule.someMethod(); // global object, "namespace"
And on the server side:
var yourModule = require( '../yourModule.js' );
yourModule.someMethod(); // local variable :-)
Just FYI, .. means "parent directory". This is the relative path of where to get the module. If the file were in the same directory, you'd use ..

NodeJS Functions/Module Include Scope

I'm developing an application with node.js and socket.io. I have built a small-scale project with some variables and functions inside a connection-specific block. These functions have access to the variables declared within that block without the need to pass the values in specifically.
This works fine, and is acceptable for a project of this size. However, as I was trying to clean the code up a bit, I looked into factoring those functions out into their own file and found modules declared by using exports.functionname as described here: http://nodejs.org/docs/v0.3.2/api/modules.html
However, these functions do not have access to the variables within the same block as they normally do when being require()'d in instead of actually being declared in the file.
Is there some way to make functions in an external file behave as if they were declared locally in nodejs?
There isn't without hacking the module system, which is exactly what I did. https://github.com/Benvie/Node.js-Ultra-REPL/blob/master/lib/ScopedModule.js
I can't say I recommend it for production. Basically the issue is more with JavaScript itself. Node wraps modules in a function so they have their own private scope. The only way to share in that scope is to be executed inside that function which wouldn't really work for a module (modular...) system. The only other scope is global which also isn't desirable.
The trick I used to get around it is in changing that wrapper function to have dynamic properties based on an externally defined set of module imports so that from inside the module wrapper all those parameters look like they're magically defined but aren't global.
Node's module wrapper looks like this:
(function (exports, module, require, __filename, __dirname){
/**module**/
})
Where mine simply adds more parameters and ensures they're resolved before executing the module wrapper.
I have it read a file named ".deps.json" in a given folder before loading a module.
An example one would be like this
[{
"providers": [ "./utility/",
"./settings/" ],
"receivers": [ "*" ]
}]
So it will load the modules in those subfolders and then expose each one as a parameter in the wrapper, named based on the filename.
The usual and clean way would be to define a function in your module, that takes the required variables as parameters:
// extracted_file.js
exports.handler = function(param1, param2) {
return param1 + param2;
}
// caller file
var extractedHandler = require('./extracted_file').handle;
var localVar1 = 1300,
localVar2 = 37;
console.log(extractedHandler(localVar1, localVar2));
You can change function scope using toString() and the dreaded eval.
If your functions were in say lib.js as follows:-
var lib = {}
lib.foo = function() { console.log(var1) }
lib.bar = function() { console.log(var2) }
module.exports = lib
In main.js you could have this:-
var var1 = 1
var var2 = 2
var ob1 = require('./lib')
ob1.foo()
ob1.bar()
When you run it the ob1.foo() line gives a ReferenceError, var1 is not defined. This is because the scope of foo() comes from lib.js and not your main js file, and var1 is invisible to it. ob1.foo is a reference to a function with lib.js scope. You need to make a new reference with main.js scope.
To do this convert each function to string and eval it. That will create a new function with the same code but with main.js scope. Here's one way using a setMainScope method which loops through all the functions changing their scope to main.js.
var var1 = 1
var var2 = 2
var ob1 = {}
ob1.setMainScope = function(ob2) {
for(var prop in ob2) {
if( !ob2.hasOwnProperty(prop) ) {continue}
if( typeof ob2[prop] !== 'function' ) {continue}
this[prop] = eval( "(" + ob2[prop].toString() + ")" )
}
}
ob1.setMainScope( require('./lib') )
ob1.foo() // 1
ob1.bar() // 2
Now it all works nicely except eval was used. The scope of foo() and bar() is now main.js and so they 'see' var1 and var2.

Resources