How to access variable in another file in node js - node.js

I have 2 files: export.js and server.js
I'm trying to access a variable in export.js in server.js, but I get undefined.
Note that I'm using knexjs and I gave it the name 'db';
export.js
let count;
const livePending = (db) => {
db('cart')
.count('id').where('status','=','Pending')
.then(data => {
if (data[0]) {
count = data[0].count;
}
}).catch(err => res.status(400).send('DB Connection failed!'));
}
module.exports = {
livePending: livePending,
pCount: count
}
server.js
[...]
const anotherFile = require('./export');
anotherFile.livePending(db);
console.log(import.pCount);
When I try to console log inside the livePending function in export.js, I get the desired count which is 1.
The reason I'm doing this is to lessen the lines of code in my server.js.
If I do the exact same function in my server.js, I get the correct result.

I created a small node app to test a variation of your code. Two important findings:
1.
const import = require('./export');
import is reserved (as well as export). Node will throw a SyntaxError: Unexpected token if you attempt to use either one as a variable name.
2.
console.log(import.count);
In your code, you're attempting to log a variable that's already been returned. You'll notice the log statement will return undefined. Instead, create a function that you can call to get the value from the actual variable in the other file.
To make things clearer, here's a little demo to show these concepts in action.
export.js
let count;
const setCount = num => count = num;
const getCount = () => count;
// Shortcut: If the key: value is the same, we can just omit the value
module.exports = {
setCount,
getCount
}
server.js
const ex = require('./export');
ex.setCount(5);
console.log(ex.getCount()); // 5

Related

How to break a single node.js file into many?

Hi,
I have an app on node.js which consists of a single file app.js that looks like this:
//variables
app = require("express")();
//many more variables here
//functions
function dosomething {}
//many more functions here
but since its getting a little too long I would like to break it into several files, one for variables only (variables.js) and another one for functions only (functions.js) and load them from app.js like this like when you do it with php
//variables
include(variables.js);
//functions
include(functions.js);
is it even possible to do that? Or I have to include everything in one single file like I do now?
Thank you.
You can use Module.Export to export a separate file, and import it into another file using the require statement. Please check here for details:
https://www.geeksforgeeks.org/import-and-export-in-node-js/
Happy Learning :-)
Importing API Endpoints
You can do this by using app.use(...) and point each endpoint to a specific file like so:
const express = require("express");
const app = express();
// User Functions
app.use("/api/user", require("./routes/api/user"));
//Orders functions
app.use("/api/orders/", require("./routes/api/orders"));
/**
* Express Server Init
*/
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on ${PORT}`));
Then in /routes/api/user/user.js you would have something like:
const express = require("express");
const router = express.Router();
router.post("/create", (req, res) => {
try {
// Create user
} catch (error) {
console.log(error);
res.sendStatus(500);
}
});
module.exports = router;
Add and index.js inside /routes/api/user to point at the user file to keep things pretty when importing (otherwise you have to import it like /routes/api/user/user):
const user = require("./user");
module.exports = user;
Importing Single File
Not sure your use case but variables could be a bad naming convention since these values are more like constants than variables. Either way, you create it like this:
const variables = {
varibleOne: "valueOne",
varibleTwo: "valueTwo",
varibleThree: "valueThree",
};
module.exports = variables;
Then wherever you want to import it you can do:
const variables = require("./variables");
and access it like so variables.variableOneand so on.
Importing functions
You can also import different functions, say you need a file called helper.js where these are commonly functions needed all over you app, you could do something like this:
const twoDecimals = (number, decimal = ",") => {
let val = (Math.round(number * 100) / 100).toFixed(2);
return decimal === "." ? val : val.replace(".", decimal);
};
const getRandomInt = (max) => {
return Math.floor(Math.random() * Math.floor(max));
};
module.exports = { twoDecimals, getRandomInt };
Then wherever you needed you can import it by:
const { twoDecimals } = require("helper.js");
Now you have access to your helper functions anywhere.
You should get help from the JavaScript modular system (preferably COMMONJS).
For example, suppose we have two files:
1-module.js 2-app.js
So now let's create this files
module.js
let name = "hello world";
function printSomething(message) {
console.log(message)
}
//here export all function and variable
module.exports.name = name;
module.exports.printSomething = printSomething
ok so Well now it is enough that "require" this file in main file :
main.js
// we
const {name, printSomething} = require("./module.js");
printSomething(name);
for export all variable You need to create an object and specify your variables as a property:
let host = "localhost"
let dbname = "laravel_8"
let username = "root"
let password = "root"
function doSomething() {
console.log("hello");
}
module.exports = {host, dbname, username, password, doSomething}
so in main file :
const variables = require("./module.js")
//host
let host = variables.host
//dbname
let dbname = variables.dbname
//function doSomething
let doSomething = variables.doSomething;
doSomething()
// or directly
variables.doSomething()
In fact, in php we use the "->" symbol to access properties, and in JavaScript we use "."

Nodejs/Mocha - FieldValue.increment - FirebaseError: Function DocumentReference.update() called with invalid data

I have the following code:
NOTE getDb() is wrapper around admin.firestore() see the link in the end of the question for more details.
let wordRef = await getDb().
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', admin.firestore.FieldValue.increment(1))
When I execute it I get
FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: a custom object (found in field count)
How do I increment the value in node js, firestore, cloud functions?
NOTE: this problem is specific to Mocha testing, I didn't check but it will probably not fail on real env.
The problem is caused by the code using the real implementation in test, which need to be override by an emulator implementation, as explain in:
https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
Where u can also find the definition of getDb() I used in the code snipet
The following code will replace the firebase admin at run time, only when running in test env.
NOTE: this code is based on https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
and for a full solution, one need to do the same trick for db as explained in the link
//db.js
const admin = require("firebase-admin");
let firebase;
if (process.env.NODE_ENV !== "test") {
firebase = admin
}
exports.getFirebase = () => {
return firebase;
};
exports.setFirebase = (fb) => {
firebase = fb;
};
test:
// package.test.js
process.env.NODE_ENV = "test"
beforeEach(() => {
// Set the emulator firebase before each test
setFirebase(firebase)
});
import:
// package.test.js and package.js (at the top)
const { setFirebase } = require("../db.js")
code:
// package.js
let wordRef = await getDb()
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', getFirebase().firestore.FieldValue.increment(1))

Is there a way to change the mocked value of a required dependency?

I'm facing a problem I'm not able to resolve on my own, maybe some of you faced the same problem.
Let me show you what I'm trying to do, here is the mock:
let mockConfig = {name: 'dude'};
jest.mock('../../../configManager', () => mockConfig);
configManager is a dependency of the function I'm trying to test.
It works well but I want to change the returning object of configManager in another test so the tested function behaves differently.
Let me show you, here is the function I'm testing:
const config = require('../../../configManager');
module.exports = () => {
if (config.name === 'dude') {
do stuff;
}
if (config.name === 'dudette') {
do something else;
}
So, typically, I want to change the config.name to 'dudette' to be able to test the second part of my function.
Naturally, when I want to do this with an imported function, I just do:
let mockJsonQueryResult = { value: 'stuff' };
jest.mock('json-query', () => jest.fn(() => mockJsonQueryResult));
and then in the test, I directly set another value to mockJsonQueryResult:
mockJsonQueryResult = { value: 'hotterStuff' };
But I don't find any way of doing this with a dependency that returns an object, with a dependency returning a function, no problem.
Is there even any way of doing this?
Thanks in advance!
Edit: this is not the same as how to change jest mock function return value in each test? as #Dor Shinar suggested because his problem is to mock a function, even if it is inside a returning object it is still a function, I just want to change a value inside the returned object.
So, I found a solution I'm not completely satisfied with but it works:
I simply set the original full object and then for my tests, change the value of specific properties by setting them directly before calling the function I want to test.
example:
let mockConfig = { person: { name: 'dude', origin: {country: 'France'} } };
jest.mock('../../../configManager', () => mockConfig);
mockConfig.person = {};
mockConfig.person.name = 'dudette';
You don't need to mock the module at all.
If your module export is just an object with property values then just change the properties as needed.
Here is a simple working example to demonstrate:
configManager.js
module.exports = {
name: 'original'
}
code.js
const config = require('./configManager');
module.exports = () => `name: ${config.name}`;
code.test.js
const config = require('./configManager');
const func = require('./code');
test('func', () => {
expect(func()).toBe('name: original'); // Success!
config.name = 'dude';
expect(func()).toBe('name: dude'); // Success!
config.name = 'dudette';
expect(func()).toBe('name: dudette'); // Success!
})
Details
A module binding can't be directly changed to something else:
const config = require('./configManager');
config = { name: 'mock' }; // <= this doesn't work
...but you can change the properties of an object representing a module binding:
const config = require('./configManager');
config.name = 'mock'; // <= this works!
...and any code using the module will automatically see the changes.

How to solve Converting circular structure to JSON in node?

I was watching a course that showed how to make an console.log with custom configs, like the color or depending on your env mode, you show the log or not.
But i keep getting the error TypeError: Converting circular structure to JSON
and I don't know why this is happening and how to solve it.
In the course, that works fine, but it doesn't to me.
node version => v8.11.2
require('colors')
const _ = require('lodash')
const config = require('../config/config')
const noop = () => { }
const consoleLog = config.logging ? console.log.bind(console) : noop
const logger = {
log: () => {
const args = _.toArray(arguments)
.map(arg => {
if (typeof arg === 'object') {
let str = JSON.stringify(arg, 2)
return str.magenta
} else {
arg += ''
return arg.magenta
}
})
consoleLog.apply(console, args)
}
}
module.exports = logger
Edit1: arguments can be anything, since logger will be used to log things with different colors in the console.
logger.log('some thing you want to log')
logger.log() is an arrow function, so arguments are not arguments of this function (see Arrow functions: No binding of arguments), but arguments of a parent function, in this case — Node.js wrapper function that compiles modules and has arguments with circular dependencies.
Try to use common function here:
const logger = {
log() {
// ...
}
};

Nodejs required variable undefined if script file not run directly?

I apologise for the phrasing of the question - it's a bit difficult to sum up as a question - please feel free to edit it if you can clarify. Also, as this quite a complex and long query - thank you to all those who are putting in the time to read through it!
I have 4 files (listed with directory tree from project root) as part of a project I'm building which aims to scrape blockchains and take advantage of multiple cores do get the job done:
./main.js
./scraper.js
./api/api.js
./api/litecoin_api.js
main.js
const { scraper } = require('./scraper.js')
const blockchainCli = process.env.BLOCKSCRAPECLI || 'litecoin-cli'
const client = (args) => {
// create child process which returns a promise which resolves after
// data has finished buffering from locally hosted node using cli
let child = spawn(`${blockchainCli} ${args.join(' ')}`, {
shell: true
})
// ... wrap command in a promise here, etc
}
const main = () => {
// count cores, spawn a worker per core using node cluster, add
// message handlers, then begin scraping blockchain with each core...
scraper(blockHeight)
}
main()
module.exports = {
client,
blockchainCli
}
scraper.js
const api = require('./api/api.js')
const scraper = async (blockHeight) => {
try {
let blockHash = await api.getBlockHashByHeight(blockHeight)
let block = await api.getBlock(blockHash)
// ... etc, scraper tested and working, writes to shared writeStream
}
module.exports = {
scraper
}
api.js
const { client, blockchainCli } = require('../main.js')
const litecoin = require('./litecoin_api')
let blockchain = undefined
if (blockchainCli === 'litecoin-cli' || blockchainCli === 'bitcoin-cli') {
blockchain = litecoin
}
// PROBLEM HERE: blockchainCli (and client) are both undefined if and
// only if running scraper from main.js (but not if running scraper
// from scraper.js)
const decodeRawTransaction = (txHash) => {
return client([blockchain.decodeRawTransaction, txHash])
}
const getBlock = (blockhash) => {
return client([blockchain.getBlock, blockhash])
}
const getBlockHashByHeight = (height) => {
return client([blockchain.getBlockHash, height])
}
const getInfo = () => {
return client([blockchain.getInfo])
}
const getRawTransaction = (txHash, verbose = true) => {
return client([blockchain.getRawTransaction, txHash, verbose])
}
module.exports = {
decodeRawTransaction,
getBlock,
getBlockHashByHeight,
getInfo,
getRawTransaction
}
So, I've taken out most the noise in the files which I don't think is necessary but it's open source so if you need more take a look here.
The problem is that, if I start the scraper from inside scraper.js by doing, say, something like this: scraper(1234567) it works like a charm and outputs the expected data to a csv file.
However if I start the scraper from inside the main.js file, I get this error:
Cannot read property 'getBlockHash' of undefined
at Object.getBlockHashByHeight (/home/grayedfox/github/blockscrape/api/api.js:19:29)
at scraper (/home/grayedfox/github/blockscrape/scraper.js:53:31)
at Worker.messageHandler (/home/grayedfox/github/blockscrape/main.js:81:5)
I don't know why, when launching the scraper from main.js, the blockchain is undefined. I thought it might be from the destructuring, but removing the curly braces from around the first line in the example main.js file doesn't change anything (same error).
Things are a bit messy at the moment (in the middle of developing this branch) - but the essential problem now is that it's not clear to me why the require would fail (cannot see variables inside main.js) if it's used in the following way:
main.js (execute scraper()) > scraper.js > api.js
But not fail (can see variables inside main.js) if it's run like this:
scraper.js (execute scraper()) > api.js
Thank you very much for your time!
You have a circular dependency between main and api, each requiring in the other. main requires api through scraper and api directly requires main. That causes things not to work.
You have to remove the circular dependency by putting common shared code into its own module that can be included by both, but doesn't include others that include it. It just needs better modularity.

Resources