Node module.exports reference own function like this keyword? - node.js

I have the following code:
module.exports.functionA = function(str) {
console.log(str);
}
In the same module, how do I call functionA? In other languages such as PHP, you can call another member of the same class using $this->functionA();
This does not work:
module.exports.functionA('Hello world!');

When functionA was assigned to module.exports it was still undefined. Instead do:
var functionA = function(str) {
console.log(str);
}
module.exports = {
functionA: functionA
}
Then the following will work:
module.exports.functionB = function() {
functionA('Hello world!');
}

Related

checking when a function in required file is used

I use a js file with a couple of functions in node which works great. But one of this functions needs to trigger a function in my main js file, and I cannot figure out how to solve this.
So I have my main.js
const externalObject = require('objectJS');
let myfunctions = require('./stuff/myFunctions.js');
myFunctions.doSomething();
and the myFunctions.js
module.exports = {
doSomething: function() {
doSomethingElse();
return data;
}
}
function doSomethingElse() {
//do some stuff
if (a) {
return something;
} else {
externalObject.action()
//or
//inform main.js to do something with externalObject
}
}
My Problem is that I have no idea how to access that external object in myFunctions.js (I cannot require it there), or how to inform my main.js that this object needs to be updated.
Any advice on this one?
Pass the function externalObject.action itself as a parameter to doSomethingElse.
const externalObject = require('objectJS');
let myfunctions = require('./stuff/myFunctions.js');
myFunctions.doSomething(externalObject.action);
The module needs to process the callback parameter accordingly:
module.exports = {
doSomething: function(callback) {
doSomethingElse(callback);
return data;
}
}
function doSomethingElse(callback) {
//do some stuff
if (a) {
return something;
} else {
callback()
//or
//inform main.js to do something with externalObject
}
}
By doing so, externalObject.action is called from inside the module and you can update the externalObject from within the externalObject.action as needed.
Just for others that may use it: After a lot of trying using eventemitter is also a solution:
myFunctions.js
let EventEmitter = require('events').EventEmitter
const myEmitter = new EventEmitter();
module.exports = {
myEmitter,
doSomething: function() {
doSomethingElse();
return data;
}
}
function doSomethingElse() {
//do some stuff
if (a) {
return something;
} else {
myEmitter.emit('action');
}
}
and in main.js
const externalObject = require('objectJS');
let myfunctions = require('./stuff/myFunctions.js');
myfunctions.myEmitter.on('action', function() {
externalObject.Action();
})
Works like a charm.

How can I mock a function/property of a node module exported as a function using sinon?

I have a service module that is exported as a function. I need to pass a couple of things into it, like a configuration object so it does need to retain this structure. I am trying to stub out a function from the service but can't figure it out. In my app, I have a function that makes an API call that is problematic during testing so I'd like to stub it. (I understand I'd have to write my test differently to handle the async issue)
// myService.js
module.exports = function(config) {
function foo() {
returns 'bar';
}
return {
foo: foo
};
};
// test.js
var config = require('../../config');
var request = require('supertest');
var chai = require('chai');
var expect = chai.expect;
var sinon = require('sinon');
var myService = require('./myService.js')(config);
describe('Simple test', function(done) {
it('should expect "something else", function(done) {
var stub = sinon.stub(myService, 'foo').returns('something else');
request(server) // this object is passed into my test. I'm using Express
.get('/testRoute')
.expect(200)
.expect(function(res) {
expect(res.body).to.equal('something else');
stub.restore();
})
.end(done);
});
});
* /testRoute I set up as a simple GET route that simply returns the value from myService.foo()
The above is not working, and I believe it has to do with the way my service is exporting. If I write the service as below, the stub works fine.
module.exports = {
test: function() {
return 'something';
}
};
But again, I need to be able to pass in information to the module so I would like to keep my modules in the original structure above. Is there a way to stub a function from a module that exports in that manner? I was also looking into proxyquire but not sure if that is the answer.
The reason why your test stub does not work is that the foo function is created every time the module initializer is called. As you discovered, when you have a static method on the module, then you are able to stub.
There are a variety of solutions to this problem-- but the simplest is to expose the method statically.
// myService.js
module.exports = function(config) {
return {
foo: foo
};
};
var foo = module.exports.foo = function foo() {
return 'bar'
}
It's ugly, but works.
What if the foo function has a closure to variables within the service (which is why it lives within the service initializer). Then unfortunately these need to be explicitly passed in.
// myService.js
module.exports = function(config) {
return {
foo: foo
};
};
var foo = module.exports.foo = function(config) {
return function foo() {
return config.bar;
}
}
Now you can safely stub the module.
However, how you are stubbing should be considered unsafe. Only if your test works perfectly does the stub get cleaned up. You should always stub within the before and after (or beforeEach and afterEach) fixtures, such as:
// We are not configuring the module, so the call with config is not needed
var myService = require('./myService.js');
describe('Simple test', function(done) {
beforeEach(function () {
// First example, above
this.myStub = sinon.stub(myService, foo).returns('something else');
// Second example, above
this.myStub = sinon.stub(myService, foo).returns(function () {
returns 'something else';
});
});
afterEach(function () {
this.myStub.restore();
});
it('should expect "something else", function(done) {
request(server) // this object is passed into my test. I'm using Express
.get('/testRoute')
.expect(200)
.expect(function(res) {
expect(res.body).to.equal('something else');
})
.end(done);
});
});
There are other options to be able to stub dependencies using dependency injection. I recommend you look at https://github.com/vkarpov15/wagner-core or my own https://github.com/CaptEmulation/service-builder

How to attach parameters to a nodejs event emmiter

I've developed a way to make two separate services to comunicate using a pub/sub channel using Redis, this is the main part of the code:
var Intercom = (function () {
var _event = new events.EventEmitter();
listener.subscribe("intercom");
listener.on("message", function(channel, message) {
try {
var data = JSON.parse(message);
_event.emit(data.controller, data.payload);
}
catch (e) {}
});
return {
on: function (evt, callback) {
_event.on(evt, callback);
},
emit: function (controller, payload) {
try {
sender.publish("intercom", JSON.stringify({ controller: controller, payload: payload}));
}
catch (e) {}
}
}
})();
Im using it on the main app just by: intercom.on('hook', hookController.main);
As you can see, if the query is "hook" the main() function of hookController is called. Its a very ExpressJs like approach.
The hookController does a very simple thing:
exports.main = function(req) {
console.log(req);
}
It is not very clear to my how the parameter "req" is getting passed to main(), and probably because of my lack of understanding about it, I cant figure it out how to pass another parameter to main from the main app, something like:
var foo = 'bar';
intercom.on('hook', hookController.main, foo);
I found a way to do it;
var foo = 'bar';
intercom.on('hook', function(req) { hookController.main(req, foo) });
Its a little bit ugly.

How to call function on shared service - SailsJS

I have service:
module.exports = {
functionA: function () {
sails.log('Hello!');
},
functionB: function () {
functionA();
}
}
then I got an error: "countPoint is not defined"
as title, I want to call another function on shared function, but I dont now how to do. Can anyone help me?
Sorry for my bad English~
FunctionA does not "exist" yet. Remember that it is a property from a JSON, not a function per se. Using quotes should help you understand:
module.exports = {
"functionA": function () {
sails.log('Hello!');
},
"functionB": function () {
functionA(); // this is actually module.exports.functionA()
}
}
Put your functions outside module.exports and reference them without ():
module.exports = {
"functionA": functionA,
"functionB": functionA
}
function functionA() {
sails.log('Hello!');
}
#nodeman: tks for your response. But I can not call function functionA() outside of module. Then I found a solution:
file Demo.js:
module.exports = {
functionA: function () {
sails.log('Hello!');
},
functionB: function () {
Demo.functionA();
}
}
by call function with file name prefix, I called function in same module.

Asynchronous nodejs module exports

I was wondering what the best approach is for configuring a module export. "async.function" in the example below could be a FS or HTTP request, simplified for the sake of the example:
Here's example code (asynmodule.js):
var foo = "bar"
async.function(function(response) {
foo = "foobar";
// module.exports = foo; // having the export here breaks the app: foo is always undefined.
});
// having the export here results in working code, but without the variable being set.
module.exports = foo;
How can I export the module only once the async callback has been executed?
edit
a quick note on my actual use-case: I'm writing a module to configure nconf (https://github.com/flatiron/nconf) in an fs.exists() callback (i.e. it will parse a config file and set up nconf).
Your export can't work because it is outside the function while the foodeclaration is inside. But if you put the export inside, when you use your module you can't be sure the export was defined.
The best way to work with an ansync system is to use callback. You need to export a callback assignation method to get the callback, and call it on the async execution.
Example:
var foo, callback;
async.function(function(response) {
foo = "foobar";
if( typeof callback == 'function' ){
callback(foo);
}
});
module.exports = function(cb){
if(typeof foo != 'undefined'){
cb(foo); // If foo is already define, I don't wait.
} else {
callback = cb;
}
}
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Multiple callback way
If your module need to be called more than once you need to manage an array of callback:
var foo, callbackList = [];
async.function(function(response) {
foo = "foobar";
// You can use all other form of array walk.
for(var i = 0; i < callbackList.length; i++){
callbackList[i](foo)
}
});
module.exports = function(cb){
if(typeof foo != 'undefined'){
cb(foo); // If foo is already define, I don't wait.
} else {
callback.push(cb);
}
}
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Promise way
You can also use Promise to solve that. This method support multiple call by the design of the Promise:
var foo, callback;
module.exports = new Promise(function(resolve, reject){
async.function(function(response) {
foo = "foobar"
resolve(foo);
});
});
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js').then(function(foo){
//Here code using foo;
});
See Promise documentation
An ES7 approach would be an immediatly invoked async function in module.exports :
module.exports = (async function(){
//some async initiallizers
//e.g. await the db module that has the same structure like this
var db = await require("./db");
var foo = "bar";
//resolve the export promise
return {
foo
};
})()
This can be required with await later:
(async function(){
var foo = await require("./theuppercode");
console.log(foo);
})();
ES6 answer using promises:
const asyncFunc = () => {
return new Promise((resolve, reject) => {
// Where someAsyncFunction takes a callback, i.e. api call
someAsyncFunction(data => {
resolve(data)
})
})
}
export default asyncFunc
...
import asyncFunc from './asyncFunc'
asyncFunc().then(data => { console.log(data) })
Or you could return the Promise itself directly:
const p = new Promise(...)
export default p
...
import p from './asyncModule'
p.then(...)
Another approach would be wrapping the variable inside an object.
var Wrapper = function(){
this.foo = "bar";
this.init();
};
Wrapper.prototype.init = function(){
var wrapper = this;
async.function(function(response) {
wrapper.foo = "foobar";
});
}
module.exports = new Wrapper();
If the initializer has error, at least you still get the uninitialized value instead of hanging callback.
You can also make use of Promises:
some-async-module.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
main.js
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
The same can happen in a different module and will also resolve as expected:
in-some-other-module.js
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
Note that the promise object is created once then it's cached by node. Each require('./some-async-module') will return the same object instance (promise instance in this case).
Other answers seemed to be partial answers and didn't work for me. This seems to be somewhat complete:
some-module.js
var Wrapper = function(){
this.callbacks = [];
this.foo = null;
this.init();
};
Wrapper.prototype.init = function(){
var wrapper = this;
async.function(function(response) {
wrapper.foo = "foobar";
this.callbacks.forEach(function(callback){
callback(null, wrapper.foo);
});
});
}
Wrapper.prototype.get = function(cb) {
if(typeof cb !== 'function') {
return this.connection; // this could be null so probably just throw
}
if(this.foo) {
return cb(null, this.foo);
}
this.callbacks.push(cb);
}
module.exports = new Wrapper();
main.js
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
main2.js
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});

Resources