mocha/chai testing hangs on await tojson().fromFile, postman passes - javascript

So, basically I am developing my first MERN stack project in which I have an api endpoint which resets the collection vehicles. I delete the data from the collection, then I parse the data from a csv and convert them to json and insert the new data. When running my backend code, everything runs smoothly in postman and robo3T. But when I run my testing code, the execution hangs at the instruction:
const vehicles_model = await tojson().fromFile(vehicles_csv);
and consequently the testing fails (res.status 500 is returned). Also, while running the testing code, the endpoint fails to run in postman, as well. What am I doing wrong?
PS: It is my first time writing on stackoverflow, if I haven't made the problem clear, I'll be happy to elaborate :)
this is my endpoint
exports.postResetVehicles = async (req, res) => {
const vehicles_csv = "vehicles.csv";
try {
Vehicles.deleteMany({}).then(function () {
console.log("Data deleted and");
});
const vehicles_model = await tojson().fromFile(vehicles_csv);
Vehicles.insertMany(vehicles_model).then(function () {
console.log("data inserted"); // Success
console.log("=>Data reseted");
}).catch(function (error) {
console.log(error); // Failure
});
return res.status(200).json({ "status": "OK" });
} catch (err) {
return res.status(500).json({ "status": "failed", "error": err });
}
};
and this is my testing code
describe("Testing 'admin/resetvehicles'", () => {
it("should succeed if Vehicles collection is reset", async () => {
const response = await request(app).post(
"/interoperability/api/admin/resetvehicles"
);
expect(response.status).to.equal(200)
});
});

Related

No able to update data using react + express

I'm trying to update data from ui but data does not update though it can be done using postman and in payload data is also being passed.
Here is handle submit function:
enter code here
data.append("thingsTodo", values.thingsTodo);
data.append("minDaysToSpent", values.minDaysToSpent);
data.append("usp", values.usp);
data.append("geoRegion", values.geoRegion.value);
data.append("altitude", values.altitude);
data.append("thingsToConsider", values.thingsToConsider);
try {
const response = await axios.put(`/api/place/${id}`, data).then((data)=>console.log(data,"data"));
controller:
exports.updatePlace = async (req,res) => {
try {
let place = Place.findById(req.params.id)
if(!place){
return res.status(404).json({success:false,message:"Place does not exists"})
}
console.log(req.body)
place = await Place.findByIdAndUpdate(req.params.id,req.body,{new:true})
res.status(200).json({
success:true,
message:"Place Updated Successfully",
place
})
} catch (error) {
return res.status(500).json({
success:false,
error:error.message
})
}
}

Getting cal cancelled error in firebase cloud functions

Firebase cloud functions logs "Error: 1 CANCELLED: Call cancelled" sometimes. am trying to send the push notifications one day before the timestamp, everything works till getting the fcm tokens but not able to send notification here is my code.
const NotificationLive_dayBefore = async () => {
try {
const path = models.payments.firebasePath;
let imageURL = null;
let tokens = [];
let subscribedUsers = await getSubscribedUsers().catch(e => { console.log(e) });
if (subscribedUsers && subscribedUsers.length > 0) {
for(const subscriber of subscribedUsers){
const userDoc = db
.collection('Payments').doc('v1').collection('users')
.doc(subscriber)
.collection('subscriptions').where('deleted_at', '==', null)
.get() // <------------here is the error according to logs
.then(async (snapshot) => {
if (!snapshot.empty) {
console.log('snapshot.empty', snapshot.empty);
for(const doc of snapshot.docs ){
// let friend_doc_id = doc.data().friend_doc_id
console.log("Friend id", doc.id);
if (doc.exists) {
let oneDay = new Date().getTime() + (24 * 60 * 60 * 1000);
let oneDayMinus1 = new Date().getTime() + (23 * 60 * 60 * 1000);
console.log(oneDayMinus1);
console.log(oneDay);
try {
let liveLesson = await db
.collection('Lessons').doc('v1').collection('friends')
.doc(doc.id)
.collection('live')
.where('start_time', '>', new Date(oneDayMinus1))
.where('start_time', '<', new Date(oneDay))
.where('deleted_at', '==', null)
.get();
for( const liveSnap of liveLesson.docs){
console.log("liveSnapid", '=>', liveSnap.data());
console.log('Private lesson exists', liveSnap.exists);
if (liveSnap.exists) {
// time is equal send notification
console.log("Subscriber ID", subscriber);
const Users = db
.collection(models.notification.firebasePath)
.where('deleted_at', '==', null)
.where('__name__', '==', subscriber)
.get()
.then(async (UserSnapshot) => {
for( const userdoc of UserSnapshot.docs){
const userdocument = userdoc.data();
if (userdocument.fcm_token) {
tokens = userdocument.fcm_token;
}
console.log('tokens',tokens);
if (tokens.length>0) {
try {
let live_lessons_images = await db
.collection('Accounts').doc('v1').collection('friends')
.doc(doc.id)
.get();
if (!live_lessons_images.data().image_url) {
imageURL = null;
console.log("Image not found");
} else {
imageURL = live_lessons_images.data().image_url;
}
} catch (error) {
console.log('That did not go well.', error)
}
console.log("notification sent live lesson 24 hr before");
await sendNotificationNew(
"test",
test notification,
imageURL,
tokens
).catch(error => { console.error("promise 1", error) });; //send notification to users as a remainder for live lesson before one day
}
}
}).catch(error => { console.error("promise 1", error) });
}
}
} catch (error) {
console.log('That did not go well.', error)
}
} else {
console.log("friend_doc_id is not present");
}
}
}
}).catch(error => { console.error("promise error", error) });
} //end foreach of subscribed user
}
return Promise.all('success');
}
catch (err) {
// Handle error here
// This will return error from api
console.log("Exceptions: ", err);
}}
and my sendNotificationNew function is
const sendNotificationNew = async (title, body, image, tokens) => {
console.log("title", title);
if (tokens.length > 0) {
if(tokens.length>1){
tokens = tokens[tokens.length-1];
}
try {
let message = {
notification: {
title: title,
body: body
},
token: tokens
};
if (image) {
message.notification.image = image;
}
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
console.log('Error sending message:', tokens);
});
} catch (err) {
console.log(err);
}
} else {
console.log("Token not available");
}
};
i was able to see the logs printing "title" of the notification, but not "Successfully sent message" or "Error sending message:".
Error message i got
Error: 1 CANCELLED: Call cancelled
at Object.callErrorFromStatus (/workspace/node_modules/#grpc/grpc-js/build/src/call.js:31)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client.js:327)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:299)
at (/workspace/node_modules/#grpc/grpc-js/build/src/call-stream.js:145)
at processTicksAndRejections (internal/process/task_queues.js:79)
And this
Error: 9 FAILED_PRECONDITION: The requested snapshot version is too old.
at Object.callErrorFromStatus (/workspace/node_modules/#grpc/grpc-js/build/src/call.js:31)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client.js:327)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:299)
at (/workspace/node_modules/#grpc/grpc-js/build/src/call-stream.js:145)
at processTicksAndRejections (internal/process/task_queues.js:79)
3rd Edit: Finally I've found the solution to this problem. A same error occurred in 2 cloud functions and I solved both of them by following the same process.
I'm not deleting the previous wrong answers, which didn't work for me, so that you also could know what won't work.
This error occurs because the Firestore has hit a limit.
I was trying to do lots of writes and updates in Firestore in parallel.
Example: Here all the functions are called all together. This is very fast as all the tasks are done in parallel. And recommended by Firebase.
But this might hit a limit in firestore and give error.
exports.botsCompletingLectures = functions.region('asia-south1')
.database.ref('triggerCloudFunctions/botsCompletingLectures')
.onUpdate(async(change, context)=>{
const promises = [];
promises.push(doSomeTaskInFirestore());
promises.push(doAnotherTaskInFirestore());
promises.push(doSomeMoreTaskInFirestore());
function doSomeTaskInFirestore(){
//Write to lots of documents in a collection
}
async function doAnotherTaskInFirestore(){
//Update lots of documents in firestore
}
async function doSomeMoreTaskInFirestore(){
//Do more tasks in firestore
}
return Promise.all(promises);
});
Solution: Here only one task will execute at a time and so it will take little more time. But will not give any error.
exports.botsCompletingLectures = functions.region('asia-south1')
.database.ref('triggerCloudFunctions/botsCompletingLectures')
.onUpdate(async(change, context)=>{
await doSomeTaskInFirestore()
await doAnotherTaskInFirestore()
return doSomeMoreTaskInFirestore()
function doSomeTaskInFirestore(){
//Write to lots of documents in a collection
}
async function doAnotherTaskInFirestore(){
//Update lots of documents in firestore
}
async function doSomeMoreTaskInFirestore(){
//Do more tasks in firestore
}
});
2nd Edit: The Cloud Function worked well for 4-5 days and then started giving errors again.
So this time I've given up on trying to fix it and instead enabled Retry on failure in Cloud Functions.
In my case as the Cloud Function is running correctly for some days and gives error on other days, due to some temperory problems, like network issue or cold start, so I can enable it here.
We should not enable it, if the error is permanent for eg a Bug in the code, else the function will keep on retrying for 7 days.
You can learn about Enabling Retry in Cloud Functions from this video.
https://www.youtube.com/watch?v=Pwsy8XR7HNE
1st Edit: The error appeared again the next day
So after reading and searching about it, I found out this problem occurs because of Cold Starting of a function after a long time and some Network problem and memory leak and most of the people (including me), who are getting this error, are getting it in PubSub Cloud Function and while doing some tasks in Firestore.
So I used a workaround. I don't know if it is recommended or not, but I'm tired of these errors, so I just did it.
I created a PubSub Cloud Function that updates a field value in Realtime Database. And this update in the field will trigger another function, that will do the task in firestore.
exports.triggerTheMainFunction = functions.pubsub.schedule('40 11 * * *').onRun(async(context)=> {
return admin.database().ref()
.child('triggerOtherFunction')
.child('doSomeTaskInFirestore')
.set(admin.database.ServerValue.increment(1))
.catch((error)=>{
console.log('Error incrementing the value', error);
});
});
And converted the Actual Function for Firestore from PubSub to Event Triggered. And since then I'm not getting any errors.
exports.doSomeTaskInCloudFirestore = functions
.database.ref('triggerOtherFunction/doSomeTaskInFirestore')
.onUpdate(async(change, context)=>{
//Do the task that was needed to be done in firestore.
});
If I get any errors in future, then I'll update this answer.
First Answer
I also got a similar error. I don't know what was causing the problem. But I solved it by installing the latest version.
So first I saved a copy of index.js on desktop and reinstalled everything.
I was using NodeJS 14 version. So I uninstalled it from control panel and downloaded the nodeJS 16 version from the nodejs website. And installed it.
ran in terminal.
npm install -g npm
then
npm install npm#latest -g
Then
firebase init
then
npm install -g firebase-tools
And then redeployed the same cloud function, without making any changes. And test run the function. And the error disappeared.
I resolved this issue by adding indexes in the firestore and proper catch blocks to all the promises to avoid unhandled rejection errors.

How to hold a node api execution till a db query does not return null

Seems rather like an unwanted requirement for a piece of code but in my case this is exactly what I need. I have an api (API-1) that interacts with a third party service. This third party service instead of directly giving me a response that I can forward back to frontend is giving me response on API-2 (With a webhook listener endpoint). I'm saving this API-2 response that I get by listening to the webhook in my database. Now I somehow need this response which is now sitting idol in my database in my API-1 so that I can forward it back to the frontend. If I query the database right away during the flow of the API-1 (Just after consume the third party service API), I'll get null as API-2 is getting the response asynchronously with a webhook (Mostly a gap of 1-2 seconds). So I somehow need to figure out an easy way to await/hold the API-1 flow till the database does not return null/returns back the response I saved from API-2 in the database. I'm not sure if the gap will always be 1-2 seconds hence I can't be using setTimeout for this.
//API-1
const sendPaymentRequest = async (req, res) => {
try {
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data);
//Check result i.e response from http listener
const webhookResponse = await MpesaModel.findOne({
conversationId: data.ConversationID
});
console.log('Webhook response => ', webhookResponse); //This is null
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//API-2 - This is the webhook which receives the response
const saveWebhookB2C = async (req, res) => {
const { Result } = req.body;
//console.log('Mpesa webhook data received => ', Result);
let saveResponse = new MpesaModel({
...Result,
});
const result = await saveResponse.save();
console.log('B2c mpesa to kenya saved in db => ', result);
res.status(200).send();
};
Just wait until the response is different than null:
let webhookResponse = null;
while (response === null) {
await sleep(1000);
webhookResponse = await MpesaModel.findOne({
conversationId: data.ConversationID,
});
}
The sleep function should be fairly simple (and we use it only to wait one second until the next query):
const sleep = (timeInMilliseconds) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), timeInMilliseconds);
});
};
Note: the while loop will run forever if the answer is always null, so probably you want to add another condition to the while in case the result is always null (maybe a maximum number of tries?).
async function getNotNullResponse({conversationId}){
const webhookResponse = await MpesaModel.findOne({conversationId});
return webhookResponse || getNotNullResponse({conversationId});
}
//API-1
const sendPaymentRequest = async (req, res) => {
try {
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data);
//Check result i.e response from http listener
const webhookResponse = await getNotNullResponse({
conversationId: data.ConversationID
});
console.log('Webhook response => ', webhookResponse); //This is not null
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//API-2 - This is the webhook which receives the response
const saveWebhookB2C = async (req, res) => {
const { Result } = req.body;
//console.log('Mpesa webhook data received => ', Result);
let saveResponse = new MpesaModel({
...Result,
});
const result = await saveResponse.save();
console.log('B2c mpesa to kenya saved in db => ', result);
res.status(200).send();
};

Expressjs router with Firestore resolves before data is retrieved

EDIT: I found out that "async" could be added to the function signature, and while the output does go in the proper order, I still get an error that I can't set headers after they are sent, even though I am not setting them anywhere else. I've modified the code to reflect this.
I'm having an issue with my Google Firestore api using ExpressJS. It seems that the result is sent before the Firestore query completes and I'm not sure why, as I'm not doing anything with res otherwise. It seems that Firestore queries are async but I don't know how to have my endpoint wait for the Firestore data before sending results. Here is my router code:
router.post('/some_endpoint/get_something', async function (req, res) {
console.log("Getting firestore data...")
let db_data = null;
let some_val = req.body.some_val;
let colRef = db.collection("some_collection");
await colRef.where("some_field", "==", some_val)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
db_data = doc.data()
})
res.json({ <---- This is where it breaks
status: 200,
data: db_data
})
})
.catch(function(error) {
console.log("Error getting doc: ", error);
})
console.log("We're done!")
});
This is the output order (EDIT with new output order):
Getting firestore data...
Still processing...
Error getting doc: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client...
We're done!
The error message is telling you that you're trying to send multiple responses, which is not valid. Here, your code is calling res.json() many times, once for each document in the query results:
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
res.json({
status: 200,
data: doc.data()
})
})
You should only call res.json() once with the final result to send to the client, after you're done iterating the results.

Facebook Graph API in aws lambda failing

I'm having trouble getting this to run. It runs just fine if I make the same FB.api call directly from the front end or through "serverless invoke local" and it console.logs my response. But when I deploy this function to a lambda and try to call it, I hit the "console.log("TRY"), get a 502 error, and then nothing after that. No response from the FB.api call, no errors, no info at all. I've tried upping the timeout as well and have brought it up to as much as 15 seconds and still getting no response. Anyone else run into this? Thanks!
export async function main(event, context, callback){
var FB = require('fb');
const data = JSON.parse(event.body)
console.log("DATA: ", data)
const requestString = data.Id + '/accounts'
console.log(requestString)
console.log("ACCESS TOKEN: ", data.accessToken)
const pages = []
try{
console.log("TRY")
await FB.api(requestString, 'get', { access_token: data.accessToken }, function(response){
console.log("RESPONSE: ", response)
callback(null, success(response));
})
}
catch (e){
console.log("CATCH")
console.log(e)
callback(null, failure({ status: false }));
}
}

Categories

Resources