How to solve UnhandledPromiseRejectionWarning in NodeJS testing framework - javascript

I'm using custom commands in my testing framework based on Nightwatch.js. I want to do a PUT request via superagent. This os my custom command:
const superagent = require("superagent");
exports.command = function(url, header, body, callback) {
return superagent
.put(url)
.send(body) // sends a JSON post body
.set(header)
.then(result => {
callback(true, result);
return this;
})
.catch(err => {
if (err) {
callback(false, err);
return this;
}
});
};
And this command I'm using in my tests:
return client
.apiPut(apiUrl, header, body, function(status, result) {
assert.isTrue(status, "response status is false");
assert.isTrue(result.ok, "response result is NOT ok");
})
If everything is fine with the PUT request (status == true and successful response) then everything is fine and the test will finish, but if the PUT request is not successful (status != true and an error as result) I'm getting the following error message and the current Node process does not finish:
09:11:12 (node:103) UnhandledPromiseRejectionWarning: AssertionError: response status is false: expected false to be true
09:11:12 at /var/jenkins_home/jobs/MYJOB/workspace/testautomation/end2end-web-tests/pageobjects/MyPageView.js:59:20
09:11:12 at superagent.put.send.set.then.catch.err (/var/jenkins_home/jobs/MYJOB/workspace/testautomation/end2end-web-tests/commands/apiPut.js:14:9)
09:11:12 at <anonymous>
09:11:12 at process._tickCallback (internal/process/next_tick.js:189:7)
09:11:12 (node:103) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
09:11:12 (node:103) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
But I don't know what I'm doing wrong with the callback in my custom command. What should I do to solve that issue?

Thanks for the help. Now it is running. I've replaced the promise and replaced it completely with callbacks. Now it is working :)
const superagent = require("superagent");
exports.command = function(url, header, body, callback) {
return superagent
.put(url)
.send(body) // sends a JSON post body
.set(header)
.end((error, result) => {
if (error) {
callback(false, result, error);
} else {
callback(true, result, error);
}
});
};

Related

Unhandled promise rejection nodejs

I am trying to use openweather-apis to connect to a dialogflow agent. I am new to promises and I keep getting the warning UnhandledPromiseRejectionWarning and I'm not sure on how to fix this.
Currently I have 2 files weather.js, which makes the api call
const api = require("openweather-apis")
api.setAPPID(process.env.API_KEY)
api.setUnits("metric")
module.exports = {
setCity: function(city) {
api.setCity(city)
},
getWeather: function() {
return new Promise(function(resolve, reject) {
api.getTemperature(function(err, temp) {
if (err) reject(err)
resolve(temp)
})
})
}
}
And I make use of weatherinCity.js, which retrieves the city from the agent, calls the calling function and then sends a response to the user.
const weather = require("../../weather")
module.exports = {
fulfillment: function(agent) {
const city = agent.parameters.geo_city
weather.setCity(city)
weather.getWeather().then(function(temp) {
agent.add(
"It is ${temp} degrees Celcius in ${city}"
)
}).catch(() => {
console.error("Something went wrong")
})
}
}
full error message:
(node:2896) UnhandledPromiseRejectionWarning: Error: No responses defined for platform: DIALOGFLOW_CONSOLE
at V2Agent.sendResponses_ (C:\Users\Coen\Desktop\ciphix-ca-case\node_modules\dialogflow-fulfillment\src\v2-agent.js:243:13)
at WebhookClient.send_ (C:\Users\Coen\Desktop\ciphix-ca-case\node_modules\dialogflow-fulfillment\src\dialogflow-fulfillment.js:505:17)
at C:\Users\Coen\Desktop\ciphix-ca-case\node_modules\dialogflow-fulfillment\src\dialogflow-fulfillment.js:316:38
at processTicksAndRejections (internal/process/task_queues.js:93:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2896) UnhandledPromiseRejectionWarning: Unhandled promise
rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was not
handled with .catch(). To terminate the node process on unhandled
promise rejection, use the CLI flag `--unhandled-rejections=strict` (see
https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode).
(rejection id: 1)
(node:2896) [DEP0018] DeprecationWarning: Unhandled promise rejections
are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.
This error indeed happened because this code fails to handle the Promise Rejection. While I'm not sure which Promise Rejection that failed to handle, but based on this and this GitHub discussions. It seems you need to return the agent.add() function.
I recommend trying async-await style with the consequence that you have to add a try catch block
module.exports = {
fulfillment: async function(agent) {
try {
const city = agent.parameters.geo_city
weather.setCity(city)
let temp = await weather.getWeather()
agent.add(
"It is ${temp} degrees Celcius in ${city}"
)
} catch (err) {
console.error("Something went wrong")
console.error(err)
}
}
}
Every error that is thrown on the try block should be caught in a catch block. Don't forget to add async before the function.
it will not solve your problem but generally speaking, i would add "return" after if(err). because otherwise the call to resolve would be done. in your particular case it will do no harm, as because of the nature of promises it will be ignored. but if you had written anything between reject and resolve it would have been executed.
// best practice
if (err) return reject(err)
for your problem, i've just tried this fast test to convice myself that even throws are catched by .catch() so i think you must be running a bad/old nodejs version, or the code you provided is not complete, and the failure is elsewere. I dont see any line pointing to your own code in the log O_o (only node_modules).
which nodejs version is it ?
var p = new Promise((resolve, reject) => {
throw new Error('test');
resolve('ok')
})
p.then(console.log).catch(function(err) {
console.error('err', err)
});

Unhandled promise rejections and ERR_HTTP_HEADERS_SENT

i'm trying to make a rest api server with node express and mysql, the structure of the requests is this:
this is the route
router.get('/api/courseDetails/:id', async (req, res) => {
try {
let levels = await db.levelsByCourseId(req.params.id)
res.sendStatus(200).json(levels)
} catch (e) {
console.log(e)
res.sendStatus(500)
}
})
and this is the query:
requests.levelsByCourseId = (id) => {
let query = "select * from levels where parent_course_id="+id+" and visibility>0"
return new Promise((resolve, reject) => {
pool.query(query,(err, results) => {
if (err) {
return reject(err)
}
return resolve(results)
})
})
}
i use this structure also for other requests that works without errore, but this gives me this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:485:11)
at ServerResponse.header (C:\Users\giuse\VScodeProjects\noderest-tutorial-server\node_modules\express\lib\response.js:771:10)
at ServerResponse.json (C:\Users\giuse\VScodeProjects\noderest-tutorial-server\node_modules\express\lib\response.js:264:10)
at C:\Users\giuse\VScodeProjects\noderest-tutorial-server\server\routes\index.js:47:29
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
(node:15588) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:485:11)
at ServerResponse.header (C:\Users\giuse\VScodeProjects\noderest-tutorial-server\node_modules\express\lib\response.js:771:10)
at ServerResponse.contentType (C:\Users\giuse\VScodeProjects\noderest-tutorial-server\node_modules\express\lib\response.js:599:15)
at ServerResponse.sendStatus (C:\Users\giuse\VScodeProjects\noderest-tutorial-server\node_modules\express\lib\response.js:357:8)
at C:\Users\giuse\VScodeProjects\noderest-tutorial-server\server\routes\index.js:50:13
at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:15588) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:15588) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
anyone could help me?
thank you
edit:
on the client side i have a promise and not some data (it is inside the promise)
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "OK"
and the axios code:
static async getCourseDetails(id) {
try {
const data = await axios.get(basepath + '/api/courseDetails/' + id)
return data.data
} catch (error) {
throw error;
}
}
You used wrong method to set status before sending results to a client.
It should be like this:
res.status(200).json(levels)
Calling setStatus you actually do res.status(200).send('OK') and right after that you call json that also sets status 200 and send a result as JSON.
The issue lies in the way you send the response. In the try block you await the levels from the db and then use sendStatus set a status and with json(levels) send a response as JSON back.
But according to the docs of Express.js sendStatus does the following.
res.sendStatus(200) // equivalent to res.status(200).send('OK')
So the status is being sent as a response. And after that you send another response as JSON. This is what triggers the error.
Use res.status(200) instead to only set the status without sending it.
router.get('/api/courseDetails/:id', async (req, res) => {
try {
let levels = await db.levelsByCourseId(req.params.id)
res.status(200).json(levels)
} catch (e) {
console.log(e)
res.sendStatus(500)
}
})

How do I handle the UnhandledPromiseRejectionWarning in Node.JS

I have a few methods that use the request module to get images from URLs and returns it as a Promise, it works but when the image isn't found it rejects the promise with the status code 404. I looked into that warning and it is said that to handle the rejection you have to setup a catch callback after then() but I don't use then(), I use async/await.
This is the code to get the picture:
/**
* Returns picture from S3
* #param {String} filename Name of the file with extension
* #returns {String} Base64 string of the file
*/
getPictureFromS3: function (filename) {
return new Promise((resolve, reject) => {
let url = this.getURLFromS3(filename);
request(url, (err, res, body) => {
if (err) reject(err);
if (res.statusCode !== 200) {
reject(`Invalid status code <${res.statusCode}>`);
}
resolve(new Buffer.from(body).toString('base64'));
});
});
}
And this is how I call the method:
try{
socket.on('server get pictures', () => db.getPictures(data=>{
if(data!==null){
data.forEach(async e=>{
let picture = await utils.getPictureFromS3(e.getFilename());
});
}
}));
}catch(err){
console.log(err);
}
Full warning:
(node:256) UnhandledPromiseRejectionWarning: Invalid status code <404>
(node:256) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which
was not handled with .catch(). (rejection id: 1)
(node:256) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Using Node v10.14.2.
There are two problems here
You care trying to do async operation inside forEach which doesn't work with promises. You need to use for..of loop or Promise.all if you can do things in parallel.
The exception is raise inside the listener so it will not bubble up outside so your catch wouldn't be executed. You need to move your try catch inside. Something like this
socket.on("server get pictures", () =>
db.getPictures(data => {
if (data !== null) {
for(const e of data) {
try {
let picture = await utils.getPictureFromS3(e.getFilename());
} catch (err) {
console.log(err);
}
}
}
})
);

UnhandledPromiseRejectionWarning when using a SoapClient

I am new in node.js, and I am experimenting things recently. A few days ago, I have tried to send a XML request to an API, with the use of easysoap-request. It worked perfectly, but I would have had to create an XML file for each different query, so I tried with easysoap. I found myself stuck pretty quickly, but I managed to resolve some issues with the help of this website. Now my program give an error that I have trouble understanding. Here my code first:
const EasySoap = require('easysoap');
const request = (async () => {
const params = {
host : 'https://someapi.com',
path : '/dir/soap',
wsdl : '/dir/wsdl',
headers: [{
'user-agent': 'Request-Promise',
'Content-Type': 'text/xml',
}]
}
var soapClient = EasySoap(params);
soapClient.call({
method :'one_methode',
attributes: {
xmlns: 'https://someapi.com'
},
params: {
'api' : {
'authentication' : {
'login' : 'mylogin',
'password' : 'mypassword'
},
'params' : {
'another_params' : {
'name' : 'Brian',
}
}
}
}
}).then((callResponse) => {
console.log(callResponse.data); // response data as json
console.log(callResponse.body); // response body
console.log(callResponse.header); //response header
}).catch((err) => {
throw new Error(err);
});
});
request();
And the error it give me:
node:10264) UnhandledPromiseRejectionWarning: Error: Error: no wsdl/xml response at soapClient.call.then.catch (C:\Users\user\Documents\src\script.js:40:15) at process._tickCallback (internal/process/next_tick.js:68:7) (node:10264) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:10264) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Is this a problem with the .catch() ? Can someone explain me ? Thanks
It's because you're throwing error inside catch, which is wrapped to Promise.reject since it's thrown inside async function, and not catching anywhere.
...
}).catch((err) => {
throw new Error(err);
});
You can either handle the error in that block like console.error(err)
or handle in your request() function call like
// request returns promise since you wrapped it in async function
request()
.catch(err => console.error(err))

UnhandledPromiseRejection in Express.js

I hope I'm supplying enough information for this question, but I can't understand why my callback function returns Unhandled Promise Rejection when I on purpose want to catch the error:
(node:3144) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
(node:3144) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm calling the function here in routes:
router.route("/home/create")
.post(Authorization, function(req, res) {
CreateSnippetResource(req, function(err) {
if (err) {
console.log(err.message)
}
res.redirect("/home")
});
});
And the "CreateSnippetResource"-function:
(function() {
let User = require("../../Models/User");
let Snippet = require("../../Models/Snippet");
/**
* Create a new snippet and save it to database
* #param request
* #param callback
*/
module.exports = function(request, callback) {
callback(
User.findOne({ user: request.session.Auth.username }, function(err, user) {
if (err || user === null) {
callback("User not found")
}
var snippet = new Snippet({
title: request.body.snippetName.split(".").shift(),
fileName: "." + request.body.snippetName.split(".").pop(),
postedBy: user._id,
snippet: [{
text: " "
}]
});
snippet.save().then().catch(function(err) {
callback(err)
});
}))
};
}());
I'm trying to handle the error when title is not entered. I have a validator in my schema-module that looks like this:
SnippetSchema.path("title").validate(function(title) {
return title.length > 0;
}, "The title is empty");
And indeed the returned error-message from the callback CreateSnippetResource is The title is empty. So how come I get this Promise-error?
I'm assuming it has something to do with how I handle the snippet.save(), but can't see how it's not handled. Can you please help?
Why does my callback function return Unhandled Promise Rejection when I on purpose want to catch the error?
That will happen when your callback throws another exception. This will reject the promise returned by the .catch(…) call, and that rejection is nowhere handled.
As it turns out, I was an idiot, and forgot that I accidentally putted the whole function in the callback. The callback is then executed twice, and thus returns Error: Can't set headers after they are sent.

Categories

Resources