Issues with exports - javascript

I'm currently trying to build an array of functions. I have a folder full of modules where each module has a function run and the following line
exports.run = run;
var run = function(db){
// Run some code
}
I then have a file I call in node which does the following:
require("fs").readdirSync("./channels").forEach(function(file) {
var func = require("./channels/" + file);
channels.push(func);
console.log("Adding " + file);
console.log(channels);
});
The function above successfully adds in each file with type undefined. I'm unable to run the functions because of this. How can I successfully build this array of functions?

The reason your code doesn't work as you expect it to, is variable hoisting in JavaScript.
var run = function(db){
// Run some code
}
exports.run = run;
If you don't want to push your exports line to the bottom of your function, then you'll have to declare run as a stand-alone function, rather than assigning it to a variable.
exports.run = run;
function run(db){
// Run some code
}

Related

Why do I get "ReferenceError: test is not defined"

Within my Google Script Project I got two GS files Code.gs and other.gs.
code.gs looks like
var globalSettings = {};
settings();
function settings(){
other();
globalSettings.fileName = "file";
console.log("settings was executed");
}
function primary(){
console.log("primary was executed");
}
other.gs looks like
function other(){
console.log("other was executed");
}
when I run the function primary I get
ReferenceError: other is not defined
settings # Code.gs:5
(anonymous) # Code.gs:1
when I move the function other to the file code it works. Could someone explain why? Is there any way the other file could be anywhere in the project?
Explanation:
Everytime you call a function (in any script in your project), the global variables are automatically executed.
This is why if you define var globalSettings = {} as a global decleration, every time you run any function in the project, all the global calls will be executed and therefore globalSettings will be set to an empty object and this is why I don't use global variables.
The global call other and the function decleration other need to be in the same gs script in order to work. Or you could simply call other from within the functions settings or primary and in this way other can stay in a separate script.
For example this would work perfectly fine:
code.gs
// define global variables
var globalSettings = {};
// adjust global variables here as a helper function
function settings(){
other();
globalSettings.fileName = "file";
console.log("settings was executed");
}
// main function to be executed
function primary(){
settings(); // call settings
console.log(globalSettings.fileName);
console.log(globalSettings.date);
console.log("primary was executed");
}
other.gs
// make additional adjustments to the global variables
function other(){
globalSettings.date = "today";
console.log("other was executed");
}
Suggestion:
A better idea to make sure you don't execute your global declerations, is to use the Class PropertiesService class to store some script or user data and then you can retrieve them either globally or locally (inside the functions) and this will make sure you won't execute them accidentally upon every execution as it is the case for the global declerations.

After stubbing function still it calls the real function

I have stubbed the content of file, so I can run through only outer function
file.html
<body onload ="test('file.txt')">
<body>
file.js
const fs1 = require('fs');
let param;
module.export = {
test,
test1,
param
}
function test (outputParam) {
let fileData = test1(outputParam);
param = fileData;
}
function test1(outputParam) {
let data = fs1.readFileSync(outputParam);
return data;
}
Here as you see I load function test from html onload and in turn test1 calls and reads file, I have stubbed this file content as shown in the test below
When I run the test I want to see the variable param has the file content value
test.spec.js
let sinon = require("sinon");
let filejs = require('./file.js');
it('should run only the outer function' ,function() {
// I try to stub my function here
sinon.stub(filejs,'test1').callsFake ((someArg) => {
return "this is my file content";
});
// Now I will call my test function
filejs.test(someArg);
})
As you seen above I have stubbed function test1, still when I run the test I see test1 gets called and it reads the real file.
I am using mocha , I am new to stub or mock concepts, any suggestion is really appreciated.
You should probably try to stub readFileSync.
const fs = require('fs');
// ...
sinon.stub(fs, "readFileSync").callsFake ((someArg) => {
return "this is my file content";
});
Besides that, I can spot two issues with your code.
The real readFileSync will return a Buffer if called without a second parameter, not a string like your stub does.
The body onload event only exists inside the DOM. The fs module is only available in Node.js. If you run your code in a browser, you won't be able to use fs.readFileSync. If you run it in Node, your HTML file and the onload event won't be useful.

exporting a function in node.js

I am using nodejs and webdriver for automation tests. I am trying to export a function from one js file to another. e.g there is a function called abc under file abc.js and i want to use that function with other file called xyz.js. I tried using export and require but it exports and runs entire test (abc.js) instead of just a function.
//abc.js
console.log('print this');
client= function client() {
driver.get(baseUrl + '/#/login');
};
exports.client = client;
//xyz.js
var client1 = require('abc.js').client();
Requiring a module for the first time causes the module to be cached and it's code to be executed, that's why you're seeing your "print this" log. Next time you call your client function you shouldn't see it.
This is not relevant to the question, but still, in your xyz.js file, since your function isn't returning anything you can use:
require('abc.js').client();
Instead of:
var client1 = require('abc.js').client();
In your abc.js, there's no need for a named function, you can just use:
var client = function() {
...
};
give it a try
function abc(){
console.log('print this');
this.client= function client() {
driver.get(baseUrl + '/#/login');
};
return this;
}
module.exports = abc;
//xyz.js
var abc = require('abc.js')();
abc.client();
its a good practice when capsulating objects in nodejs

Appjs run function after node.js function has ran

I am trying to make a simple read file function in my Appjs program. All that is happening is that the Appjs is calling a function inside my app.js file and running it in node.js. This function then returns a value to my Appjs program by window.returnData = data;
This works, however I can't get it to work in the order I want. The node.js function seems to be running AFTER the Appjs function although it is inside of it.
Here is the function inside of my Appjs index.html file that starts the entire process.
var returnData;
function r(path,d) {
window.readFromFile(path,d); //call to the function readFromFile below
alert(returnData);
}
readFromFile() function from the app.js file that Is being called from above
window.readFromFile = function(path,d) {
var fs = require('fs');
if (d == 1) {
path = __dirname + path;
}
fs.readFile(path, {encoding: 'utf-8'}, function(err,data){
if (err){
console.log(err);
} else {
console.log('File read');
window.returnData = data;
}
});
}
Here is my problem. The first call of this function will alert the text undefined. However, after the alert function, I know that the window.returnData = data; line above is working because if I create a button to alert the variable returnData again or I run the readFromFile function again, it alerts the data correctly.
Am I incorrect in thinking that the child function should complete first? Is there a way around this? I don't want to create a loop that continuously checks for the variable to change.
Thanks in advance.

Executing imported Javascript functions in order

I want to execute 2 functions in a specific that I have imported from 2 other .js files that I have made. The function that needs to complete first takes a bit of time and the 2nd one starts before the first is ended and I need files the first one created for it to work. Here's basically what my .js looks like:
var pdfToPng = require("./pdfToPng.js");
var doStuffToPng = require("./doStufftoPng.js");
var pdfFilePath = process.argv[2];
var pngFilePath = pdftoPng.convert(PdfFilePath);//convert takes a path
//and makes a png and returns path
//to the png
doStuffToPng.doStuff(pngFilePath);
//I want "doStuff()" to start AFTER "convert()" is done.
Im pretty sure it has something to do with callbacks, but I'm a javascript noob and need help. I can get it to work with setTimeout(), but that seems like a "duct tape fix" to me. Is there some way more elegant?
Edit: some wonderful people wanted to help and asked to post this, the pdfToPng.js:
var spindrift= require('spindrift');//this is a node module
var fs = require('fs');
//Makes a png from pdf in pngFolder and returns the path to that png
exports.convert = function(path)
{
var pdf = spindrift(path);
var pathToPng = path.substring(0, path.length-4); //takes off the .pdf
pathToPng += "_out.png";
//this is spindrift's stuff, makes a png in dir pngFolder/pathToPng
pdf.pngStream(500).pipe(fs.createWriteStream("pngFolder/" + pathToPng));
return "pngFolder/" + pathToPng;
}
Welcome to the async world of javascript. The function callback though created synchronously is executed asynchronously. So you have to modify the code to get doStuff executed only after you know for sure that convert function has executed. You can find how this can be done # Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
if so, you need to implement your own callback,
- Open pdftoPNG.js
- modify convert function with one more parameter
function convert(PdfFilePath, finishConvert) {
//now just insert this line where you finally instead of return
//remove return yourpngpath; //or something, i assume
//add following in the place of return
finishConvert(yourpngpath);
}
Then Please call like this
var pdfToPng = require("./pdfToPng.js");
var doStuffToPng = require("./doStufftoPng.js");
var pdfFilePath = process.argv[2];
pdftoPng.convert(PdfFilePath,function(path){
if(path!="") {
doStuffToPng.doStuff(path);
}
});
You have to update your convert method to support callbacks/ promises.
Here is an example using Callbacks
exports.convert = function(path, fnCallback)
{
var pdf = spindrift(path);
var pathToPng = path.substring(0, path.length-4); //takes off the .pdf
pathToPng += "_out.png";
//this is spindrift's stuff, makes a png in dir pngFolder/pathToPng
pdf.pngStream(500).pipe(fs.createWriteStream("pngFolder/" + pathToPng));
if (fnCallback && typeof(fnCallback) === "function") {
fnCallback("pngFolder/" + pathToPng);
}
}
You'll see the following
A new parameter being passed in fnCallback
A check to make sure that the parameter is passed in and that it is a function
The fnCallback function gets called with the results passed in as a parameter
Removing of the return statement
Now when the convert method is called, after the long running process completes, the Callback method will get executed.
To call the modified convert method you now have to pass in a callback function
function myCallback(path){
// do something with the path
}
pdftoPng.convert(PdfFilePath,myCallback);

Categories