I have created a node module
Module file :
var functions = {};
functions.test = function(){
console.log("Invoked");
return "Hello";
}
module.exports = functions;
Main File :
const FUNCTIONS = require('./modulefile');
var x = FUNCTIONS.test();
console.log(x);
Now, here I can see "Invoked" means function is getting executed.
But x is undefined, seems value is not getting returned.
How can I return value from test() to main file.
You could use callbacks?
Hard to say what the underlying problem is considering people have got your code working.
Model file:
var functions = {
test: function(callback) {
console.log("Invoked");
callback("Hello")
}
}
module.exports = functions;
Other file:
var Functions= require('./functions');
var x
Functions.test(function (result) { x = result });
console.log(x);
Your code works just fine, I replicated it and it works
check it out here https://repl.it/#Muhand1/module-export
Related
UPDATE: I've figured it out. Thank you to eol for getting me thinking about the promise. While the recommended script didn't get me there, the thinking did.
To get the object to pass properly, I needed to start with the object itself and restructure the code to support that end.
var barBuildX = function(csv, domainColumnName, rangeMin, rangeMax, paddingInner, paddingOuter) {
var x = {
rMin: rangeMin,
rMax: rangeMax,
padIn: paddingInner,
padOut: paddingOuter,
domain: (function() {
var dom = [];
d3.csv(csv).then(function(data) {
data.forEach(function(d) {
dom[dom.length] = d[domainColumnName];
});
})
return dom;
})(),
};
console.log(x);
return x;
};
};
This is a fairly basic subroutine meant to populate an object with the fields necessary to satisfy a d3.js scaleBand() function. The first part of this script is working as expected - building an array of domain names based on the "domainColumnName" within the supplied CSV file. However, the second part, where we actually build the "x" object that will be returned, is not functioning properly - not writing to console or carrying back any of the data I'm attempting to pass to it. This is especially annoying seeing as it should just be setting property values and returning the object for use elsewhere... Any thoughts?
var barBuildX = function(csv, domainColumnName, rangeMin, rangeMax, paddingInner, PaddingOuter) {
var dom = [];
d3.csv(csv).then(function(data) {
console.log(data); //this works
data.forEach(function(d) {
dom[dom.length] = d[domainColumnName];
});
console.log(dom); //this works
var x = {
domain: dom,
rMin: rangeMin,
rMax: rangeMax,
padIn: paddingInner,
padOut: paddingOuter
};
console.log(x); //this DOES NOT work
return x; //Undefined... / Type Error
});
};
There was a note of differences in variable spellings, that was unfortunately a mistake I made when copying over to this thread. There are no differences in variable spellings in the original source that isn't working.
The error message I'm getting in the Chrome console is: "Uncaught TypeError: Cannot read property 'domain' of undefined"
So, the return object is coming in as undefined...
You're not returning the promise from within your function, which is why you'll get undefined as a return value. Do something like this:
var barBuildX = function(csv, domainColumnName, rangeMin, rangeMax, paddingInner, PaddingOuter) {
var dom = [];
return d3.csv(csv).then(function(data) {
console.log(data); //this works
data.forEach(function(d) {
dom[dom.length] = d[domainColumnName];
});
console.log(dom); //this works
var x = {
domain: dom,
rMin: rangeMin,
rMax: rangeMax,
padIn: paddingInner,
padOut: paddingOuter
};
console.log(x); //this DOES NOT work
return x; //Undefined... / Type Error
});
};
// how to invoke the function:
barBuildX(...).then(x => {
console.log(x);
});
How do I call a simple addition function and assert the result of two values using selenium-cucumber-js framework with a test written below. While running the below it says
TypeError: TypeError: Cannot read property 'addvalues' of undefined
at createWorld.When (C:\Tests\cucumber\step-definitions\addvalues-steps.js:5:25)
Feature:
Scenario: Addition of two values
When Add two values 5 and 10
Then I should get result 15
// Here is my 'addvalues-steps.js' file
const expect = require('chai').expect;
module.exports = function () {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, (x, y) =>{
this.page.addvalues.addValues(x,y);
})
this.Then(/^I should get result (-?\d+)$/, (ans) =>{
let tot = this.page.addvalues.addValues(x, y);
expect(tot).to.be.eql(ans);
})
};
// Following is my 'addvalues.js file'
module.exports = {
addValues(x,y){
var total = x + y ;
return total ;
}
};
// world.js >>
const { CustomWorld } = require('cucumber')
function CustomWorld() {
console.log('overriding the world')
this.page = {
addvalues: require('../page-objects/addvalues')
}
console.log("This is the recent error log:"+this.page.addvalues)
}
module.exports = function() {
this.World = CustomWorld;
Note: the below example is for an old version of cucumber-js: 1.3.3.
With cucumber.js, when you're referencing this from inside step definitions, you're actually referencing the World context. So, for this.page.addvalues.addValues(x,y); to work properly, you'll first need to create page that has a reference to your addvalues.js. Something along these lines:
world.js:
function CustomWorld() {
console.log('overriding the world')
this.page = {
addvalues: require('../page-objects/addvalues')
}
}
module.exports = function() {
this.World = CustomWorld;
};
addvalues.js:
//addvalues.js
module.exports = {
addValues(x,y){
var total = x + y ;
return total ;
}
};
There's also a couple of things to correct in your steps.js.
Don't pass arrow functions into the steps, as this will remove the this context that you're setting in World.js.
If you want to share variables between steps (as you do in your example), you need to store them somewhere. One such place, again, would be the World context. Note how in my version I set this.prevResult
When the variables are injected into your steps, they are injected as strings. Note the parseInt() in my version.
addvalues-steps.js:
const expect = require('chai').expect;
module.exports = function() {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, function (x, y) {
this.prevResult = this.page.addvalues.addValues(parseInt(x, 10), parseInt(y, 10));
})
this.Then(/^I should get result (-?\d+)$/, function (ans) {
let tot = this.prevResult;
expect(tot).to.be.eql(parseInt(ans, 10));
})
}
UPD: It turns out that the question is about selenium-cucumber-js, which is a framework on top of cucumber-js. Disregard the comments about the world.js.
According to selenium-cucumber-js docs, you don't need this to access the page objects in your step definitions:
Page objects are accessible via a global page object and are
automatically loaded from ./page-objects.
const expect = require('chai').expect;
module.exports = function() {
this.When(/^Add two values (-?\d+) and (-?\d+)$/, function (x, y) {
this.prevResult = page.addvalues.addValues(parseInt(x, 10), parseInt(y, 10));
})
this.Then(/^I should get result (-?\d+)$/, function (ans) {
let tot = this.prevResult;
expect(tot).to.be.eql(parseInt(ans, 10));
})
}
I've looked through a few questions related to this error, and most of them seem to be a misunderstanding of what the keyword this means. I don't think I'm having that problem here. Mine might be some sort of circular dependency problem that I cannot articulate well enough to figure it out on my own.
I've tried to distill my problem into three files presented below.
something.js
var A = require('../lib/a');
var Something = function (type) {
this.type = type;
};
Something.prototype.setTemplate = function (template) {
this.template = template;
};
Something.prototype.applyTemplate = function () {
var templateResult = this.template.calculate();
};
var factory = {};
factory.createSomething = function(type) {
return new Something(type);
};
factory.createA = function (input) {
return A.Make(input);
};
module.exports = factory;
a.js
var S = require('../prof/something');
var _ = require('underscore');
var A = function (input) {
this.input = input;
};
A.prototype.calculate = function () {
var calculation = 0;
var _s = S.createSomething('hello world');
// do calculation using input
return calculation;
};
var factory = {};
factory.Make = function (input) {
var a = new A(input);
return a;
};
module.exports = factory;
a_test.js
describe('Unit: A Test', function() {
var S = require('../prof/something');
it('test 1', function() {
var a = S.createA({
//input
});
var s = S.createSomething('type1');
s.setTemplate(a);
s.applyTemplate(); // error
});
});
The error gets thrown from the top level in a_test.js on the line with the comment //error. At the lowest level, the 'is not a function ' error is thrown in a.js at the S.createSomething(type) method. It says that S.createSomething() is not a function.
I've put a breakpoint in at that line and tried to call functions from the underscore library, but it gives the same error. So it seems that the require statements inside a.js are not throwing errors, but none of the injected objects can be used to call functions from. The a_test.js file is being run with the karma library.
Am I violating some javascript paradigm by referencing back and forth between A and S? How can I do this properly?
Edit: I've done some further testing. It doesn't actually matter if the test file looks like this:
describe('Unit: A Test', function() {
var S = require('../prof/something');
it('test 1', function() {
var a = S.createA({
//input
});
a.calculate(); // error
});
});
An error is still thrown at the line indicated above.
The files in the question reference each other. This is called cyclic dependencies. The solution is to move the var S = require('../prof/something'); statement into the calculate function like so:
a.js
// move the line from here
var _ = require('underscore');
var A = function (input) {
this.input = input;
};
A.prototype.calculate = function () {
var S = require('../prof/something'); // to here
var calculation = 0;
var _s = S.createSomething('hello world');
// do calculation using input
return calculation;
};
var factory = {};
factory.Make = function (input) {
var a = new A(input);
return a;
};
module.exports = factory;
Github source for reference
Files where issue exists: updateDB.js, quickstart.js
Inside quickstart.js I have set a variable updateDB on line 2:
var updateDB = require('./updateDB.js');
which I believe refers to my updateDB.js file (which is currently living in the same folder).
However later in the file when I try to call a function from updateDB.js on line 118:
updateDB.inputFormToDB(rows);
I get the error "updateDB.inputFormToDB is not a function".
Inside updateDB.js I have things set up as follows:
var updateDB= function() {
some function
var inputFormToDB = function(parameter) {
function code
}
some function
some function
};
module.exports = updateDB;
Am I missing something to call my function from inside quickstart.js??? I feel like I'm making some small mistake somewhere.
The problem is in
var updateDB = function() {...}
should be
var updateDB = {...}
like a Object.
e.g.
var updateDB = {
inputFormToDB: function() {...}
}
or
var updateDB = function() {
var x = ...
function inputFormToDB() {...}
return {
inputFormToDB: inputFormToDB
}
}
I use mocha to test a function in a file. The testable function is implemented like this:
math.js
(function (exports) {
var MY_APP_ = MY_APP || {};
MY_APP_.utils = MY_APP_.utils || {};
MY_APP_.utils.math = MY_APP_.utils.math || {};
MY_APP_.utils.math.randomValue = function (min, max) {
return Math.floor(Math.random() * (max + 1 - min) + min);
};
exports.math = MY_APP_.utils.math;
})(this);
And here is the test:
math_test.js
var assert = require("assert");
var math = require("../../js/utils/math.js");
describe('Math', function() {
describe('randomValue', function () {
it('should return random values', function () {
// Fill array with random values between 0 and 10
var values = [];
for (var i = 0; i < 10000; i++) {
values.push(math.math.randomValue(0, 10));
}
// Count numbers
var result = {};
values.forEach(function(number) {
var numberAsString = number.toString();
result[numberAsString] = result[numberAsString] + 1 || 1;
});
// There must be at least two of each number
assert.equal(Object.keys(result).length, 11);
Object.keys(result).forEach(function(key) {
assert.equal(true, result[key] > 1);
});
});
});
});
The problem is that var MY_APP_ = MY_APP || {}; fails with an error message: MY_APP is not defined.
Sure, MY_APP is not defined in the scope of this test because it is defined in an another file called app.js. When I build the app, this app.js file is included before math.js and both of them are concatenated into a single production.js file. This works without problem.
The test works, however, if I replace the failing line with the following:
var MY_APP = {};
if (typeof(MY_APP) !== 'undefined') {
MY_APP_ = MY_APP;
} else {
MY_APP_ = {};
}
This looks stupid in my opinion. I would like to know the reason why mocha is failing since the code works perfectly well when I run it in a browser.
EDIT:
I think I have made a mistake. var MY_APP_ = MY_APP || {}; seems to never work if MY_APP is not defined so the only option is to declare MY_APP before using math.js
From what you showed I would think that you would receive an error, and that your direct test works.
In your test you initialize MY_APP to an empty object which allows it to run. But in your math.js file MY_APP is never initialized, so when you set var MY_APP = MY_APP it would never be able to set it to anything.
I would suggest trying to initialize MY_APP before assigning it as a value for a variable.
Since the only purpose of app.js to just initialize var MY_APP = {}; to global scope I decided to do the same in the test file, so:
var assert = require("assert");
global.MY_APP = {};
var math = require("../../js/utils/math.js");
solves the problem