I am trying to run a test with jest, except it cannot find my function. I am exporting multiple functions from one file using module.exports = {}.
Here is my test file:
const queries = ('../config/queries');
test('Check Activation Code. -- checkActivationCode(test#gmail.com, 0123456789) ', () => {
let email = 'test%40gmail.com';
let code = 1234567890;
let result = "";
queries.checkActivationCode(email, code, function(error, result) {
if (error) result = false;
else result = true;
});
expect(result).toBe(true);
});
My file structure is as follows, /config/queries/index.js, I am able to access the functions in my other files just fine.
Here is my queries/index.js file:
module.exports = {
checkActivationCode: function(email, code, callback) {
pool.getConnection(function(error, connection) {
connection.query('SELECT code FROM confirmation WHERE email = ?', [email.toLowerCase()], function(error, results) {
if (error) callback(error);
try {
if (results[0].code === code) {
callback(null, true);
} else {
callback(null, false);
}
} catch (e) {
callback(null, false);
}
});
connection.release();
});
}
}
I forgot to require my queries.
const queries = ('../config/queries');
to
const queries = require('../config/queries');
Simple typo. Thanks #BenceGedai for catching that.
Related
I have a simple web application for uploading zip files to a server. In the Javascript part I have used a try-catch block for checking whether the files are password protected(A predefined and known password) by reading the entries and catching the corresponding error.
The js library which I am using is https://github.com/gildas-lormeau/zip.js/blob/master/dist/zip.min.js.
let reader;
try {
reader = new zip.ZipReader(new zip.BlobReader(file), {
password
});
const entries = await reader.getEntries();
for (const entry of entries) {
try {
await entry.getData(new zip.BlobWriter(), {
onprogress: (index, max) => {
zip.BlobWriter.$cancel()
reader.close()
}
});
} catch (error) {
if (error.message === zip.ERR_ENCRYPTED ||
error.message === zip.ERR_INVALID_PASSWORD) {
alert("Incorrect password")
return false;
} else {
console.log(error)
}
}
}
} catch (error) {
console.log(error)
} finally {
await reader.close();
}
The above code successfully finds out if the file is not encrypted by the predetermined password. However, for some files the error statement is as below.
TypeError: Cannot read properties of undefined (reading 'importKey')
I would like to know why this happens and how to know whether the file is password protected or not.
Thank You
There are some issues with the code you proposed, for example BlobWriter.$cancel is not documented anywhere and does not exist actually. Also, you should call reader.close() only once.
Here is below how such a function could be written.
const verifyZipPassword = async (file, password) => {
const reader = new zip.ZipReader(new zip.BlobReader(file), { password });
const entries = await reader.getEntries();
try {
for (const entry of entries) {
const abortController = new AbortController();
const signal = abortController.signal;
const onprogress = () => abortController.abort();
await entry.getData(new zip.BlobWriter(), { signal, onprogress });
}
} catch (error) {
if (error.message == zip.ERR_INVALID_PASSWORD) {
return false;
} else if (error.message != zip.ERR_ABORT) {
throw error;
}
} finally {
await reader.close();
}
return true;
};
I have a function that gets data from AWS:
main.js
const { GetInstancesByName } = require("./functions");
var operationmode = "getinstances";
if (operationmode == "getinstances") {
let getresult = GetInstancesByName(instance);
console.log("(getinstances log)",getresult);
let resultsent = "yes";
callback(getresult);
}
then this is the functions file (functions.js):
functions.js
const GetInstancesByName = function GetInstancesByName(name) {
let ec2 = new AWS.EC2({apiVersion: '2016-11-15'});
//console.log(ec2);
let params = {
Filters: [
{
Name: "tag:Name",
Values: [
name
]
}
]
};
ec2.describeInstances(params, function(err, data) {
if (err)
console.log("error",err, err.stack); // an error occurred
else return data; // successful response
/*
data = {
}
*/
});
return data;
};
I am trying to get the data from the (error , data) in the function. I have tried: setting a var/const/let to the data. the return data at the bottom works but data is empty. I want to get data so I can pass it back in the GetInstancesByName (being used by main.js).
on the main both console.log("(getinstances log)",getresult) and callback(getresult); both return not defined.
Any help would be much appreciated.
Thank You
If you don't want to use async/await, you may pass a callback to GetInstancesByName as follows:
function GetInstancesByName (name, callback) {
// ...
ec2.describeInstances(params, function(err, data) {
if (err) {
console.log("error",err, err.stack); // an error occurred
} else {
callback(data); // successful response
}
});
// ...
}
// In main.js
GetInstancesByName(instance, data => {
// do something with data
});
For some reason, I can't get values returned from module.exports function from a separate custom module. I tried many ways from many sources from >10s researched posts. If you want to vote down, please read my bio or if you want to help I will be happy to accept your answer.
// restapi/index.js
module.exports = function gifs() {
giphy.search('Pokemon', function (err, res) {
return res.data[0];
});
}
// main server.js
var readapi = require('restapi')
console.log(readapi.gifs());
// Output:__________________
TypeError: readapi.gifs is not a function
You are exporting a function, not an object with a function and you are using a sync function (console.log) with an async operation.. it won't work.
You need to write it like this:
module.exports = function gifs(cb) {
giphy.search('Pokemon', function (err, res) {
if(err) { cb(err) }
else { cb(null, res.data[0]) }
});
}
----
var readapi = require('restapi')
readapi((err, data) => { console.log({err, data}) })
Remember the difference between:
module.export = {
hello: () => { console.log('world') }
}
// usage: require('./hello').hello()
module.export = () => { console.log('world') }
// usage: require('./hello')()
Try this code
module.exports.gifs = function gifs() {
return new Promise((resolve, reject) => {
giphy.search('Pokemon', function (err, res) {
if (err) reject(err);
else resolve(res.data[0]);
});
});
}
// main server.js
var readapi = require('restapi')
readapi.gifs().then(console.log);
conn.connect(function (err) {
if (err) throw err;
var prizeCode = generatePrizeCode();// this method return a 5-digit code
var query = "SELECT * FROM user WHERE code = ? ";
var values = [[prizeCode]];
conn.query(query, [values], function (err, result) {
if (err) throw err;
// Here I want to re-execute the above query if the result is not empty
});
});
In the above code, I want to execute query as long as the result contain data. But I cannot use the loop like following pseucode,
// if the result is empty, the generated code does not exist in database. So it can be used.
while(result.length != 0){
var result = conn.query("SELECT * FROM user WHERE code = abc");
}
How can I achieve this?
You'll have to use callbacks or promises/async functions. Here's how it could be written with callbacks:
const mysql = require('mysql');
const retryLimit = 50;
const connection = mysql.createConnection({
database: 'test',
host: 'localhost',
password: 'hunter2',
user: 'dave',
});
function getData(attempts, cb) {
if (attempts < retryLimit) { // we haven't exausted our attempts yet
const code = generatePrizeCode();
connection.query('SELECT * FROM user WHERE code = ?', code, (err, result) => {
if (err) {
return cb(err);
}
if (result.length > 0) { // code already exists
getData(attempts + 1, cb); // recurse
} else { // this is a new code
cb(null, code); // return the new code via the callback function
}
});
} else { // we have exausted our attempts
return cb(new Error('retry limit exceeded'));
}
}
getData(0, (err, code) => {
// do what you want here, e.g., console.log(code)
connection.end();
});
Note that this can cause node to crash if you recurse too many times and exceed the maximum call stack. One way around that is to call setImmediate or setTimeout instead of recursing directly. Instead of the line
getData(attempts + 1, cb); // recurse
use
setImmediate(() => {
getData(attempts + 1, cb); // recurse
});
or
// recurse, using setImmediate every 1000th time
if (attempts % 1000 === 0) {
setImmediate(() => {
getData(attempts + 1, cb); // recurse
});
} else {
getData(attempts + 1, cb); // recurse
}
Using promises and async/await style would clean this up a lot and probably look more like what you're used to (note this uses the promise-mysql library):
const mysql = require('promise-mysql');
async function getData(connection) {
const retryLimit = 50;
for (let i = 0; i < retryLimit; i++) {
const code = generatePrizeCode();
const result = await connection.query('SELECT * FROM user WHERE code = ?', code);
if (result.length === 0) { // this code doesn't exist yet
return code;
}
}
throw new Error('retry limit exceeded');
}
(async () => {
try {
const connection = await mysql.createConnection({
database: 'test',
host: 'localhost',
password: 'hunter2',
user: 'dave',
});
try {
const code = await getData(connection);
// do what you want here, e.g., console.log(code)
} finally {
connection.end();
}
} catch (err) {
console.log(err);
}
})();
basically you gonna need to work with async\await or promises(pretty much the same).
https://javascript.info/async-await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
this way your gonna be able to only return when you get the right result for you.
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'YOUR_HOST_NAME',
user : 'YOUR_USER_NAME',
password : 'YOUR_PASSWORD',
database : 'YOUR_DATABASE'
});
pool.getConnection(function(err, connection) {
// connected! (unless `err` is set)
});
connection = mysql.createPool
var retryLimit=0;
var getData = function () {
if(retryLimit <= 50)
{
retryLimit++;
connection.query('SELECT * FROM user WHERE code = abc', function (error, results, fields) {
if (error) {throw error;}
else if(result.length <1) {
getData();
//call the same method again.
}
});
}
}
getData();
You could add else statements and do whatever you want.
I'm trying to write a asynchronous function to create some user directories with node.js.
I would like the callback to be executed with a response containing the status of the operations for later processing. But the object is not being logged from within the for loop and the second mkdir. Also the subdirectory name is logged as the same thing even though all the directories are created correctly?
I have been looking for a while as how to solve this i think its due to closures and needs an IIFE? just i am totally lost now on how to solve it. Can anyone help point me in the right direction please?
here is my code:
const fs = require('fs');
const path = require('path');
var showSettings = {
"userDirectories": ["shows", "uploads", "backups", "logs"],
"showsFolder": "shows"
};
var Files = function() {};
Files.prototype.makeUserDirectories = (username, callback) => {
let directory = (path.join(__dirname, "../users", username));
let response = {};
fs.mkdir(directory, err => {
if (err) {
response.status = "ERROR";
response.error = err;
console.log('failed to create directory', err);
} else {
console.log(`creating directory ${directory} succeeded`);
let subdirectory = "";
for (let i = 0; i < showSettings.userDirectories.length; i++) {
subdirectory = (path.join(__dirname, "../users", username, showSettings.userDirectories[i]));
fs.mkdir(subdirectory, err => {
if (err) {
response.status = "ERROR";
response.error = err;
console.log('error creating subdirectory', err);
} else {
response.status = "OK";
console.log(`creating directory ${subdirectory} succeeded`);
};
});
}
console.log(response);
}
if (callback && typeof(callback) === "function") {
console.log(response);
callback(response);
}
});
};
testFiles.makeUserDirectories("mr.test#somedomain.com", function(data) {
console.log("in callback function");
console.log(data);
});
My problem is that the returned response object to the callback is empty.
i think its something to do with the for loop and an IIFE but i am not entirely sure how to do this or if there is abetter way to achieve what i am trying to do?
Many thanks!
Your issue is that you're trying to execute your callback before your asynchronous operations have completed. Asynchronous operations can be very complicated, and there are many libraries to make things simpler, many based on the concept of Promises. These are objects that allow you to chain multiple operations together, with the cost of more overhead. I would highly recommend using Promises to produce a more intuitive function:
const fs = require('fs');
const path = require('path');
var showSettings = {
"userDirectories": ["shows", "uploads", "backups", "logs"],
"showsFolder": "shows"
};
var Files = function() {};
function mkdir(path) {
return new Promise((resolve, reject) => {
fs.mkdir(path, (err) => {
if(err) {
reject(err);
} else {
resolve("OK");
}
})
});
}
Files.prototype.makeUserDirectories = (username, callback) => {
let directory = (path.join(__dirname, "../users", username));
return mkdir(directory).then(() => {
console.log(`creating directory ${directory} succeeded`);
let subdirectory = "";
const operations = [];
for (let i = 0; i < showSettings.userDirectories.length; i++) {
subdirectory = (path.join(__dirname, "../users", username, showSettings.userDirectories[i]));
operations.push(mkdir(subdirectory));
}
return Promise.all(operations);
}).then((status) => { // this will not be called until all operations complete
console.log({status});
if (callback && typeof(callback) === "function") {
callback({status});
}
}).catch((error) => { // this will be called if an error is encountered at any point
callback({status: 'ERROR', error});
})
};
var testFiles = new Files();
testFiles.makeUserDirectories("mr.test#somedomain.com", function(data) {
console.log("in callback function");
console.log(data);
});
EDIT: Updated with a cleaner implementation.