I am importing three js modules that I made into a program but whenever I run any of them, they always run the exported function of the last imported file.
x = require("./modules/x/x");
y = require("./modules/y/y");
z = require("./modules/z/z");
and in each of those files is a function exported as:
module.exports = { runX/Y/Z }
I would expect runX to run for x.runX, runY for y.runY and runZ for z.runZ.
However, the function that actually runs is which ever was imported last.
The code inside the modules looks something like this
const juergenJSON = require("./juergen.json");
noArg = async channel => {
};
oneArg = async (arg1, channel) => {};
twoArg = async (arg1, arg2, channel) => {};
runJuergen = options => {
const juergen = options;
juergen.twoArgs
? twoArg(juergen.arg1, juergen.arg2, juergen.channel)
: juergen.oneArgs
? oneArg(juergen.arg1, juergen.channel)
: noArg(juergen.channel);
};
module.exports = { runJuergen };
They are called like so
const { Client } = require("discord.js");
const auth = require("./auth.json");
let reddit = require("./modules/reddit/reddit.js");
let juergen = require("./modules/juergen/juergen.js");
let joe = require("./modules/joe/joe.js");
// Create an instance of a Discord client
const client = new Client();
/**
* The ready event is vital, it means that only _after_ this will your bot start reacting to information
* received from Discord
*/
client.on("ready", () => {
console.log("Bot Loaded");
});
client.on("message", message => {
let name;
let arg1;
let arg2;
const temp = message.content.split(" ");
const channel = message.channel;
name = temp[0].substr(1);
arg1 = temp[1];
arg2 = temp[2];
let oneArgs;
let twoArgs;
arg1 && true ? (oneArgs = true) : (oneArgs = false);
arg1 && arg2 ? (twoArgs = true) : (twoArgs = false);
const options = {
name: name,
arg1: arg1,
arg2: arg2,
oneArgs: oneArgs,
twoArgs: twoArgs,
channel: channel
};
switch (name.toLowerCase()) {
case "reddit":
console.log("hello");
reddit.runReddit(options);
break;
case "juergen":
juergen.runJuergen(options);
break;
case "joe":
joe.runJoe(options);
break;
case "max":
tea(arg1, message);
break;
break;
}
});
I know that there are some similar posts out there to this, but I'm having trouble understanding them so a response specific to my situation would be greatly appreciated.
Defining each const locally to its case in the switch statement solved the issue
Related
When I have this code here:
client.on("message", msg => {
const args = msg.content.trim().split(/ +/g);
let second = args[1];
let x = Math.floor((Math.random() * second) + 1);
if(msg.content === "random") {
msg.channel.send(`${x}`)
console.log(x)
console.log(second)
}
})
I need to send "random 10 (example)" twice and it still doesn't work cause it uses the "random" as the input for "second¨ how do i make this work?
Since "msg" is a string, you need to parse it as an integer before preforming an operation on it. I recommend replacing the "let x" line with the following:
let x = Math.floor((Math.random() * parseInt(second)) + 1);
parseInt is an internal function that takes a string with number contents and turns it into an integer.
const triggerWords = ['random', 'Random'];
client.on("message", msg => {
if (msg.author.bot) return false;
const args = msg.content.trim().split(/ +/g);
let second = args[1];
let x = Math.floor((Math.random() * parseInt(second)) + 1);
triggerWords.forEach((word) => {
if (msg.content.includes(word)) {
msg.reply(`${x}`);
}
});
});
To add on to quandale dingle's answer, what you can do with your bot is to create a command handler, which will make the developing process much easier and will look nice. If you don't really want to create a command handler, you can also use the following code:
if (message.content.startsWith(prefix)){
//set a prefix before, and include this if statement in the on message
const args = message.content.slice(prefix.length).trim().split(/ +/g)
const commandName = args.shift().toLowerCase()
//use if statements for each command, make sure they are nested inside the startsWith statement
}
If you want to create a command handler, there's some sample code below. It works on discord.js v13, but I've no idea if it will work in v12. This is a more advanced command handler.
/*looks for commands in messages & according dependencies
or command handler in more simple terms*/
const fs = require("fs");
const prefix = "+"; //or anything that's to your liking
client.commands = new Discord.Collection();
fs.readdirSync("./commands/").forEach((dir) => {
const commandFiles = fs.readdirSync(`./commands/${dir}/`).filter((file) =>
file.endsWith(".js")
); //subfolders, like ./commands/helpful/help.js
//alternatively... for a simpler command handler
fs.readdirSync("./commands/").filter((file) =>
file.endsWith(".js")
);
for (const file of commandFiles) {
const commandName = file.split(".")[0]
const command = require(`./commands/${file}`);
client.commands.set(commandName, command);
}
});
//looks for commands in messages
client.on("messageCreate", message => {
if (message.author == client.user) return;
if (message.content.startsWith(prefix)){
const args = message.content.slice(prefix.length).trim().split(/ +/g)
const commandName = args.shift().toLowerCase()
const command = client.commands.get(commandName)
if (!command) return;
command.run(client, message, args)
}
});
I am writing a node JS web crawler class, and I have encountered the following error, this.textInvertedIndex[word].push is not a function. Upon further inspection I realised that for some reason this.textInvertedIndex[word] was written as a native object, function Object({ [native code] }). For the first few iterations, by console logging this.textInvertedIndex everything seemed fine as it was an object of arrays. But then suddenly this error occurred. Is there any part of the code where I am implicitly rewriting textInvertedIndex?
Here is the relevant class:
function Crawler(queue, maxIndexSize) {
this.queue = queue;
this.maxIndexSize = maxIndexSize;
this.findChunks = () => {
let currentChunk;
let minimumDistance = Infinity;
for (i = 1; i <= this.maxIndexSize; i++) {
if (this.maxIndexSize % i === 0) {
const newDistance = Math.abs(i - 30);
if (newDistance < minimumDistance) {
minimumDistance = newDistance;
currentChunk = i;
} else {
return currentChunk
};
};
};
};
this.chunks = this.findChunks();
this.chunkSize = this.maxIndexSize / this.chunks;
this.totalWordOccurances = {};
this.imageInvertedIndex = {};
this.textInvertedIndex = {};
this.images = [];
this.sites = [];
this.seen = {};
this.write = (url, html) => {
const documentId = this.sites.length;
const website = new Website(url, html);
const title = website.title();
const content = website.content(title);
const words = content.filter(item => typeof item !== "object");
const wordsLength = words.length;
const query = new Query(words);
const individualWords = query.individualize(words);
this.seen[url] = true;
this.sites.push({
url,
title,
description: website.description()
});
for (word of individualWords) {
const normalizedTf = query.count(word) / wordsLength;
const textInvertedIndexEntry = {
documentId,
normalizedTf
};
if (this.textInvertedIndex[word]) {
this.textInvertedIndex[word].push(textInvertedIndexEntry);
} else {
this.textInvertedIndex[word] = [textInvertedIndexEntry];
};
if (this.totalWordOccurances[word]) {
this.totalWordOccurances[word] += 1;
} else {
this.totalWordOccurances[word] = 1;
};
};
for (i = 0; i < content.length; i++) {
const item = content[i];
if (typeof item === "object") {
const imageId = this.images.length;
this.images.push(item);
for (word of individualWords) {
const imageScore = getImageScore(i, word, content);
const imageInvertedIndexEntry = {
imageId,
imageScore
};
if (this.imageInvertedIndex[word]) {
this.imageInvertedIndex[word].push(imageInvertedIndexEntry);
} else {
this.imageInvertedIndex[word] = [imageInvertedIndexEntry];
};
};
};
};
};
this.crawl = async () => {
while (this.sites.length !== this.maxIndexSize) {
let nextQueue = [];
const websitesUnfiltered = await Promise.all(this.queue.map((url) => {
const website = new Website(url);
return website.request();
}));
const websitesToAdd = this.maxIndexSize - this.sites.length;
let websites = websitesUnfiltered.filter(message => message !== "Failure")
.slice(0, websitesToAdd);
for (site of websites) {
const url = site.url;
const htmlCode = site.htmlCode;
const website = new Website(url, htmlCode);
this.write(url, htmlCode);
nextQueue = nextQueue.concat(website.urls());
};
nextQueue = new Query(nextQueue.filter(url => !this.seen[url]))
.individualize();
this.queue = nextQueue;
};
};
};
Called like this
const crawler = new Crawler(["https://stanford.edu/"], 25000000);
crawler.crawl();
this.textInvertedIndex = {}; is defining an Object of which push is not a valid function. you can change it to an array by defining it as this.textInvertedIndex = []; otherwise you can add key/value entries to the object as it is defined like this: this.textInvertedIndex[key] = value;
Turns out, my key was accessing this.textInvertedIndex[word]. And word was constructor. constructor is already a built in object property so it can never be rewritten as an array with .push defined. To solve this problem, make all object keys capital, so constructor will become CONSTRUCTOR, thus making sure that already existing object properties are never called.
This is from a world.js in a cucumber puppeteer project.
The first code block causes an error. But if I hard code the selector as in the second code block, there is no error. How do I pass the argument into the arrow function so I don't have to hard code the selector? TIA
Hard coded selector: works
async getOriginalForecastDate(selectorTitle, selectorDate, wait = 0) {
await this.page.waitForSelector(selectorTitle);
await this.page.waitForSelector(selectorDate);
const originalDateStr = await this.page.evaluate(selectorDate => {
let result = document.querySelector('div[class="rollmodel_cal_date"]');
////let result = document.querySelector(selectorDate);
return result.innerText.trim();
});
const originalDate = utils.constructDate(originalDateStr);
return originalDate;
}
Trying to pass selector as an argument: doesn't work
async getOriginalForecastDate(selectorTitle, selectorDate, wait = 0) {
await this.page.waitForSelector(selectorTitle);
await this.page.waitForSelector(selectorDate);
const originalDateStr = await this.page.evaluate(selectorDate => {
/////let result = document.querySelector('div[class="rollmodel_cal_date"]');
let result = document.querySelector(selectorDate);
return result.innerText.trim();
});
const originalDate = utils.constructDate(originalDateStr);
return originalDate;
}
You should pass arguments after evaluate arrow function. like this page.evaluate(pageFunction, ...pageFunction arguments). docs.
async getOriginalForecastDate(selectorTitle, selectorDate, wait = 0) {
await this.page.waitForSelector(selectorTitle);
await this.page.waitForSelector(selectorDate);
const originalDateStr = await this.page.evaluate(
(selectorDate, arg1, arg2) => {
/////let result = document.querySelector('div[class="rollmodel_cal_date"]');
let result = document.querySelector(selectorDate);
return result.innerText.trim();
},
selectorDate,
arg1,
arg2,
);
const originalDate = utils.constructDate(originalDateStr);
return originalDate;
}
Lets say I have a file file1.js which contains:
const a = true;
let b;
if (a) {
b = c;
}
if (!a) {
b = d;
}
Now when I run test case on this file my first condition gets covered. Is there any way that I can cover second condition by setting a to false or should I change my code in a way that I can call a method with different values to test for each case kind of like:
const a = true;
getBVal(a) {
return a ? c : d;
}
let b = getBVal(a);
Update:
Below is my code for requestAnimationFrame with fallbacks for older browsers:
let lastTime = 0;
const vendors = ["ms", "moz", "webkit", "o"];
let rAF = window.requestAnimationFrame;
if (!rAF) {
rAF = vendors.find(prefix => window[`${prefix}RequestAnimationFrame`]);
}
if (!rAF) {
rAF = cB => {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = setTimeout(() => {
cB(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
function requestAnimationFrame(callback) {
return rAF(callback);
}
export default requestAnimationFrame;
I am using jsdom in setup for window object. Now if I have to test case for window.requestAnimationFrame = null its not possible in the way I have written my code
Now after changing it to:
import { requestAnimationFrameVendor } from "../constants";
let lastTime = 0;
const customFn = cB => {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = setTimeout(() => {
cB(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
function requestAnimationFrame(callback) {
const rAF = window.requestAnimationFrame;
return rAF && rAF(callback) || requestAnimationFrameVendor && requestAnimationFrameVendor(callback) || customFn(callback);
}
export default requestAnimationFrame;
And then if I write test like:
import * as constants from "../../constants";
describe("animationFrame", () => {
let requestAnimationFrame;
let cancelAnimationFrame;
beforeAll(() => {
requestAnimationFrame = global.window.requestAnimationFrame;
cancelAnimationFrame = global.window.cancelAnimationFrame;
});
test("requestAnimationFrame", done => {
global.window.requestAnimationFrame = null;
global.window.cancelAnimationFrame = null;
const requestId1 = Utils.requestAnimationFrame(jest.fn());
constants.requestAnimationFrameVendor = jest.fn(() => {
return requestAnimationFrame;
});
const requestId2 = Utils.requestAnimationFrame(jest.fn());
setTimeout(() => {
Utils.cancelAnimationFrame(requestId1);
Utils.cancelAnimationFrame(requestId2);
done();
}, 300);
});
afterEach(() => {
global.window.webkitRequestAnimationFrame = null;
global.window.webkitCancelAnimationFrame = null;
});
});
Then it covers all the conditions.
I would go the second rout (getBVal()) because it makes your interface more testable.
In general, removing global state (like your const a or let b) will make your code and interfaces more testable. If you cannot remove the global state completely, you can introduce abstractions so that your test does not need to know about the global state (like your suggested getBVal()).
Maybe you can go even further and remove the global b: Instead always call getBVal() instead? The performance impact will be negligible in most cases, and your code becomes even more testable and less coupled...
I´ve checked numerous posts but could not solve the issue.
I want to return the array before going on. I tried using a function with a callback but that did not work either.
My code looks as following:
exports.GetHelmets = functions.database.ref('onTrack/{userID}').onCreate(event => {
var helmets = [];
let userID = event.params.userID;
let friendRef = admin.database().ref("friends").child(userID);
friendRef.once("value").then(snapshot => {
snapshot.forEach(function(snapshot2){
let rider = snapshot2.val();
let riderID = rider.id;
let rhRef = admin.database().ref("User").child(riderID);
rhRef.once("value", function(snapshot3){
let rider2 = snapshot3.val();
let helmetID = rider2.helmet;
if (helmetID != "STANDARD"){
if(helmets.indexOf(helmetID) < 0){
helmets.push(helmetID);
};
};
});
});
return helmets;
}).then(helmets => {
//WORK WITH ARRAY
});
I hope you can help me, thanks!
You want the last then() to get all the inner data, each of which requires its own call to once(). In such a case, you'll want to use Promise.all() to wait for all the onces.
exports.GetHelmets = functions.database.ref('onTrack/{userID}').onCreate(event => {
let userID = event.params.userID;
let friendRef = admin.database().ref("friends").child(userID);
friendRef.once("value").then(snapshot => {
var promises = []l
snapshot.forEach(function(snapshot2){
let rider = snapshot2.val();
let riderID = rider.id;
let rhRef = admin.database().ref("User").child(riderID);
promises.push(rhRef.once("value");
});
});
return Promise.all(promises);
}).then(snapshots => {
var helmets = [];
snapshots.forEach((snapshot) => {
let rider2 = snapshot.val();
let helmetID = rider2.helmet;
if (helmetID != "STANDARD"){
if(helmets.indexOf(helmetID) < 0){
helmets.push(helmetID);
};
};
});
// WORK WITH helmets
});