How do you call a function from within another function in a module.exports declaration?
I have MVC structure node js project and a controller called TestController.js. I want to access method within controller, but using this keyword gives below error:
cannot call method getName of undefined
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
this.getName(data);
},
getName : function(data) {
// code
}
}
How do I access methods within controller?
I found the solution :-)
"use strict"
var self = module.exports = {
myName : function(req, res, next) {
// accessing method within controller
self.getName(data);
},
getName : function(data) {
// code
}
}
You can access the getName function trough module.exports. Like so:
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
module.exports.getName(data);
},
getName : function(data) {
// code
}
}
Maybe you could do it like this. It reduce nesting. And all your export is done at the end of your file.
"use strict";
var _getName = function() {
return 'john';
};
var _myName = function() {
return _getName();
};
module.exports = {
getName : _getName,
myName : _myName
};
If you want to use the function locally AND in other files...
function myFunc(){
return 'got it'
}
module.exports.myFunc = myFunc;
I know the answer is already accepted, but I feel the need to add my two cents on the issue.
Node modules have a "Singletonic" nature, when inside the module, you are the module.
In my opinion, at least design pattern wise, inner module methods can be accessed more cleanly, without the need for this or a copy of self for that matter.
Using this, could be dangerous, if one happens to send the separate methods around and forgets to use .bind.
Using a copy of self, is redundant, we already are inside a Singleton behaving module, why keep a reference to yourself when you can avoid that?
Consider these instead:
Option 1
// using "exports."
exports.utilityMethod = (..args) => {
// do stuff with args
}
exports.doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
exports.utility(someParam)
}
Option 2
// using module.exports
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
// either this
module.exports = {
utility,
doSomething,
}
// or
module.exports = {
customNameForUtility: utility,
customNameForDoSomething: doSomething
}
This works the same for es6 modules:
Option 1 (ES6)
export const utilityMethod = (..args) => {
// do stuff with args
}
export const doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
utility(someParam)
}
Option 2 (ES6)
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
export default {
doSomething,
utility
}
// or
export {
doSomething,
utility
}
Again, this is just an opinion, but it looks cleaner, and is more consistent across different implementations, and not a single this/self is used.
Related
I am creating a node module and I am hoping to force the user to pass an argument during module require.
Like this:
const sample = require('sample-module')('username')
Inside my sample-module, I have declared the public functions like this (these are imports from other files):
module.exports = {
addNewFolder: folderHandler.addNewFolder,
printToFile: printHandler.printToFile,
deleteFolder: folderHandler.deleteFolder
// more functions
}
// Here I want to add a function that will accept the argument passed.
function setUserName(name) {
// some handling here, in this case, 'name' is 'username' as we passed in during require
}
How can I do this?
Lastly, I prefer to require using like this:
const sample = require('sample-module')('username')
Rather than:
const sample = require('sample-module')
sample.setUserName('username')
Help anyone? Thanks!
You can change module.exports to function like this
const test = (arg) => {
console.log(arg);
};
module.exports = function (requireArg) {
return {
test: test(requireArg),
};
};
then require it
const { test } = require('./test')('apple');
I'm trying to set a unit testing boilerplate for my company. Our front end projects are built with ES6 classes and have a dependency to our core product. The front end code gets wrapped through a build process in a whole other block of code that is basically a closure and captures the dependency. So we don't have to manually import it in order to use it.
Let's say the dependency is called productScope and it's an object that has some DOM models, internal APIs and parameters among many other things necessary for each project. At the moment, Mocha throws ReferenceError: productScope is not defined. How can I mock this object? Or should I just use the actual object?
Example:
class someClass {
constructor() {
const id = productScope.items[0].id
const item = productScope.domModel.querySelector('.some-div')
item.classList.add(`added-${id}`)
}
}
This get wrapped in core code like below:
(function(productScope) {
// front end code goes here
}(productScope)
Testing file:
import someClass from '../../js/someClass'
describe('someClass', function() {
const someClass = new someClass()
it('should be a class', function() {
console.log(someClass)
});
});
You can try something like this
describe('#someClass', () => {
let someClass;
beforeEach(() => {
global.productScope = {
// mocking productScope object
};
});
it('should be a class', () => {
someClass = new SomeClass;
console.log(someClass);
});
afterEach(() => {
delete global.productScope;
});
});
or alternatively if you want more specific mock logic for each test case
describe('#someClass', () => {
let someClass;
it('should be a class', () => {
global.productScope = {
// mocking productScope object
};
// Test logic start
someClass = new SomeClass;
console.log(someClass);
// Test logic end
delete global.productScope;
});
});
Looks like productScope is a global variable.
Something like this should work for you.
import someClass from '../../js/someClass';
describe('someClass', function() {
let someClass;
beforeEach(() => {
global.productScope = {
// you mock definition
someClass = new someClass();
};
});
it('should be a class', function() {
console.log(someClass)
});
});
I'm with other answers as well, as managing global variables seems to be the simplest and most straightforward solution.
However, you can use toString to get class's string representation, and eval it to bind to closure's scope:
class someClass {
constructor() {
this.id = scopedId
}
}
// pass class as an argument
function scopeFactory(classDef) {
// define scoped data
let scopedId = 2;
// eval is used to bind class to the local closure
// so `scopedId` will be in charge
return eval("(" + classDef + ")");
}
const scopedSomeClass = scopeFactory(someClass);
console.log(new scopedSomeClass)
Note that eval(someCLass.toString()) doesn't work without parentheses.
You can add it as a helper function, into your project.
In an ExpressJS setup, I have server.js where I do the following:
import { call_method } from '../hereIam.mjs';
const process_db = async () => {
console.log(this); // undefined
call_method(this);
};
console.log(this) // undefined
process_db();
And then, from hereIam.mjs I want to call a parent method, but this is undefined
export const call_method = parent_this => console.log(parent_this); // undefined
I tried to include classes in server.js, in an attempt to force having a this
class AppServer {
constructor() {
console.log(this)
}
const process_db = async () => call_method(this);
}
But it seems that the arrow functions inside classes doesn't compile in (experimental) NodeJS (this should be another question)
EDITED
How I can do this is by avoiding the arrow notation to be able to use classes inside Express, and then instantiate a class that provides a this.
class AppServer {
async process_db() {call_method(this)};
}
let server = new AppServer();
server.process_db();
The question would be, the only way of getting a this reference is by using objects/classes?
You could use the the bind method and pass through any object to be used as the this context.
However, arrow functions receive the context from that which they are called from, function() {} function syntax use the context that was bound to them either implicitly by the context they were defined in or explicitly using this bind method.
So, an alternative to using classes would be to bind a simple object to the method, something like:
const call_method = require('../hereIam.mjs');
const process_db = async function() {
console.log(this);
call_method(this);
};
console.log(this);
const context = {
name: 'bound context',
parent_method: async function() {
console.log('Good evening');
}
}
process_db.bind(context)();
Presuming hereIam.mjs contains:
module.exports = parent_this => console.log(parent_this);
then the script will output:
{}
{ name: 'bound context',
parent_method: [AsyncFunction: parent_method] }
{ name: 'bound context',
parent_method: [AsyncFunction: parent_method] }
I have a function that returns true or false, lets call it myFunc
myFunc (){
if(something){return true}
else{return false}
}
that's what it does for sake of arg
I then call it somewhere else
if(myFunc()){
}else{
}
when I log it out, it continually comes out as false. however, when i have mocked it in my test like so:
const myMock = (myModule.myFunc = jest.fn())
myMock.mockReturnValue(true)
so why is it still coming back as false when I log it from the index file? or is that not quite how mocking works?
I'm guessing that myModule is the object you imported, and then you set the mock function on that object. But in the myModule file you are referencing that function directly, not through a module reference, right?
The proper way would probably be to move myFunc out of myModule. But if you want to keep it there, then you are going to have to partially mock myModule:
jest.mock('./myModule', () => {
return {
...jest.requireActual('./myModule'),
myFunc: jest.fn()
}
})
But seriously consider moving myFunc out of myModule, because partial mocking is difficult and confusing.
One way I found to solve my issue was to use a class instead.
Here is a sudo example:
Implementation
export class Location {
getLocation() {
const environment = this.getEnvironmentVariable();
return environment === "1" ? "USA" : "GLOBAL";
}
getEnvironmentVariable() {
return process.env.REACT_APP_LOCATION;
}
}
Test
import { Location } from "./config";
test('location', () => {
const config = new Location();
jest.spyOn(config, "getEnvironmentVariable").mockReturnValue("1")
const location = config.getLocation();
expect(location).toBe("USA");
});
I'd like to know if and how it's possible to save the following config into my modules scope (think of the block below as one module):
var config = null;
var mySingleton = {
init: function(config) {
config = config; // Naming conflict!
},
printConfig: function() {
console.log(config); // Undefined!
}
};
export { mySingleton };
Unfortunately, a naming conflict occurs. I'd need something like module.config = config;.
Note: I'm using the es6-module-transpiler.
No. It's a simple variable, and not a global one (where it would be accessible as a property of the global object), so it just is shadowed and not available "namespaced".
You need to use a different name to resolve conflicts, which should be trivial and will cause no effects outside the module:
var config = null;
var mySingleton = {
init: function(conf) {
config = conf;
},
printConfig: function() {
console.log(config);
}
};
export { mySingleton };