I'm trying to use Contentful, a new JS library for building static websites. I want to use it in Node JS.
I created an app file like this (the name is getContent.js):
'use strict';
var contentful = require('contentful')
var client = contentful.createClient({
space: '****',
accessToken: '****'
});
module.exports = client;
function getEntry() {
return client.getEntry('******')
.then(function (entry) {
// logs the entry metadata
console.log(entry.sys)
// logs the field with ID title
console.log(entry.fields.channelName)
})
}
Then I created a test (getContent.test.js) like this:
'use strict';
let chai = require('chai');
let should = chai.should();
var expect = chai.expect;
var rewire = require("rewire");
let getContent = rewire("./getContent.js");
describe('Retreive existing', () => {
it('it should succeed', (done) => {
getContent.getEntry({contentName:'****'
}, undefined, (err, result) => {
try {
expect(err).to.not.exist;
expect(result).to.exist;
// res.body.sould be equal
done();
} catch (error) {
done(error);
}
});
});
});
but I obtain this error:
Retreive existing (node:42572) UnhandledPromiseRejectionWarning:
Error: Request failed with status code 400
at createError (/Users/ire/Projects/SZDEMUX_GDPR/api/node_modules/contentful/dist/contentful.node.js:886:15)
at settle (/Users/ire/Projects/SZDEMUX_GDPR/api/node_modules/contentful/dist/contentful.node.js:1049:12)
at IncomingMessage.handleStreamEnd (/Users/ire/Projects/SZDEMUX_GDPR/api/node_modules/contentful/dist/contentful.node.js:294:11)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9) (node:42572) 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: 3) (node:42572) [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.
Do you know what I'm missing? the promise is ok, I already tested it with a simple node getContent.js
I am seeing few issues with your code:
1. Invalid Args
In your test function, in getContent.js, you are passing an argument to the getEntry method (return client.getEntry('******'), whereas you are passing an object in the test (getContent.getEntry({}))
2. Mixing Promises & Callbacks
it('it should succeed', (done) => {
getContent.getEntry("****")
.then((result) => {
console.log(result);
try {
expect(result).to.exist;
// res.body.sould be equal
done();
} catch (error) {
done(error);
}
})
.catch(error => {
console.log(error);
done(error)
})
});
3. Source of Unhandled Promise rejection is not clear:
Is it coming from your test function in getContent.js, or, is it coming from your actual test?
Probably, this could also come from,
expect(err).to.not.exist;
expect(result).to.exist;
Always catch errors in Promises and reject it with proper reason to avoid issues like this.
Could you please update your code and repost it, so that its clear for other users?
Related
I have this code, copied directly from the stripe website:
app.post('/createSubscription',async (req, res) => {
let r = (Math.random() + 1).toString(36).substring(7);
console.log(r);
const subscription = await stripe.subscriptions.create({
customer: 'cus_' + r,
items: [
{price: 'price_1InXJuIPT89VeZtCMeR3xQWf'},
],
});
})
however, when i run this code, it gives me an error in my console.
to show where the warning was created)
(node:38025) 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`
i am not sure exactly what this means, because I have never seen thsi error for stripe before? What am i doing wrong within my subscription funciotn?
You should try/catch any async function which may throw an error. For example:
let subscription;
try {
subscription = await stripe.subscriptions.create({
customer: 'cus_' + r,
items: [
{ price: 'price_1InXJuIPT89VeZtCMeR3xQWf' },
],
});
} catch (e) {
console.error(e);
// Do something about the fact that you encountered an error, example:
return res.status(500).send('Internal Error');
}
// Do stuff with subscription
This should at least log your error and prevent it from crashing the process. Once you can see the actual error causing the problem then you will be able to reference stripe's documentation.
I use Node Js 12. I have below code and error. I want to re-throw err from inner catch and catch it in outer one. How to modify my code to achieve error re-throw?? Thanks.
function test() {
try {
// Some other code before promise chain below that could cause exception
return Promise.resolve()
.then(() => {
const e = new Error();
e.message = 'testtest';
e.statusCode = 404;
throw e;
})
.catch(err => {
console.log('==inner===', err);
throw err;
});
} catch (err) {
console.log('==outer===', err);
}
}
test();
Error
jfan#ubuntu2004:~/Desktop/temp/d$ node index.js
==inner=== Error: testtest
at /home/jfan/Desktop/temp/d/index.js:17:19 {
statusCode: 404
}
(node:34826) UnhandledPromiseRejectionWarning: Error: testtest
at /home/jfan/Desktop/temp/d/index.js:17:19
(node:34826) 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:34826) [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.
jfan#ubuntu2004:~/Desktop/temp/d$
SUGGESTION
// define an async function for the purpose of awating a promise inside the function
// optional useError parameter is used to trigger an error for testing purposes
// optional args parameter is for passing any additional parameters to this function for example
async function test(useError=false, args=[]) {
try {
// Some other code before promise chain below that could cause exception
if(useError) {
throw new Error(`Some error occured while processing ${args[0]}...`);
}
// await the promise and store the result in a variable
const promisedData = await Promise.resolve(`Promise delivered with ${args[0] ? args[0] : 'nothing'}!`);
// return the result (this will be a promise)
return promisedData;
} catch (err) {
// catch error that occurs within try block
console.log('==outer===', err);
}
}
// a simple generic async function runner for example
async function genericAsyncFunctionRunner(asyncFunction, ...args) {
let [useError, ...otherArgs] = args;
useError = useError ? true : false;
const result = await asyncFunction(useError, otherArgs);
// Output the result in console for example
console.log(result);
}
// run asyn function using the generic async function runner with/without arguments
genericAsyncFunctionRunner(test); // Promise delivered with nothing!
genericAsyncFunctionRunner(test, false, 'gratitude'); // Promise delivered with gratitude!
genericAsyncFunctionRunner(test, true, 'gratitude'); // ==outer=== Error: Some error occured while processing gratitude...
I'm running an electron application with the nfc-pcsc module. When I hold my Android device close to the acr-122u, I get the following logging:
Running in development
18:52:19 – info: nfc module init
(node:30973) UnhandledPromiseRejectionWarning: Error: Cannot process ISO 14443-4 tag because AID was not set.
at ACR122Reader.handle_Iso_14443_4_Tag (/private/var/www/lab/electron-clientnfc/node_modules/nfc-pcsc/dist/Reader.js:566:26)
at ACR122Reader.handleTag (/private/var/www/lab/electron-clientnfc/node_modules/nfc-pcsc/dist/Reader.js:506:21)
at CardReader.Reader.reader.on (/private/var/www/lab/electron-clientnfc/node_modules/nfc-pcsc/dist/Reader.js:164:18)
(node:30973) 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:30973) [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 is my code:
const { NFC } = require('nfc-pcsc');
const nfc = new NFC(); // optionally you can pass logger
nfc.on('reader', (reader) => {
console.log(`${reader.reader.name} device attached`);
reader.aid = 'F222222222';
reader.on('card', async card => {
console.log(`${reader.reader.name} card detected`, card);
});
reader.on('card.off', (card) => {
console.log(`${reader.reader.name} card removed`, card);
});
reader.on('error', (err) => {
console.log(`${reader.reader.name} an error occurred`, err);
});
reader.on('end', () => {
console.log(`${reader.reader.name} device removed`);
});
});
nfc.on('error', (err) => {
console.log('an error occurred', err);
});
what is wrong with this?
I'm using a 3rd party module that wraps around their API. I have the following code:
const api = require('3rdpartyapi');
async function callAPI(params) {
try {
let result = await api.call(params);
return result;
}
catch(err) {
throw err; //will handle in other function
}
}
async function doSomething() {
try {
//...do stuff
let result = await callAPI({a:2,b:7});
console.log(result);
}
catch(err) {
console.error('oh no!', err);
}
}
Despite both try-catch blocks, the 3rd party API, when it losses connection to homebase (happens quite frequently :( ), blows up with:
(node:13128) UnhandledPromiseRejectionWarning: FetchError: request to https://www.example.com failed, reason: getaddrinfo ENOTFOUND
Followed by:
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)
How come none of my try-catch catch this? What exactly is unhandled, and how to actually handle this?
The point is the await only converts "first layer" rejection into error, however the promise can have promise inside, and their library may fail to catch the rejection inside. I have made a proof of concept 3rdpartyapi which can trigger the behavior you see:
(async function () {
// mock 3rdpartyapi
var api = {
call: async function(){
await new Promise((resolve, reject) => {
// why wrap a promise here? but i don't know
new Promise((innerResolve, innerReject) => {
innerReject('very sad'); // unfortunately this inner promise fail
reject('this sadness can bubble up');
})
})
}
};
// your original code
async function callAPI(params) {
try {
let result = await api.call(params);
return result;
} catch (err) {
throw err; //will handle in other function
}
}
async function doSomething() {
try {
//...do stuff
let result = await callAPI({
a: 2,
b: 7
});
console.log(result);
} catch (err) {
console.error('oh no!', err);
}
}
doSomething();
})();
Output:
$ node start.js
oh no! this sadness can bubble up
(node:17688) UnhandledPromiseRejectionWarning: very sad
(node:17688) 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:17688) [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.
I am learning node.js and how to test functions. I have a problem when using mocha: when functions are passing test, everything is completely fine, I get a nice looking message.
But if whichever function which doesnt pass a test - for example the result in the test is 0 but intentionally I wrote the asswertion to expect 1 - it gives me a mile long error massage in the bash-cli-console:
Async functions
(node:6001) UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]: 0 == 1
at utils.requestWikiPage.then.resBody (/home/sandor/Documents/learning-curve-master/node-dev-course/testing-tut/utils/utils.test.js:10:20)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
(node:6001) 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:6001) [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.
1) it should return a html page
0 passing (2s)
1 failing
1) Async functions
it should return a html page:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/sandor/Documents/learning-curve-master/node-dev-course/testing-tut/utils/utils.test.js)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! dev-course#1.0.0 test: `mocha ./testing-tut/**/*.test.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the dev-course#1.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/sandor/.npm/_logs/2018-07-04T11_31_53_292Z-debug.log
[nodemon] app crashed - waiting for file changes before starting...
I dont know why do I get this part: UnhandledPromiseRejectionWarning...
and why do I get this part: npm ERR! code ELIFECYCLE
the function I am testing: (it makes a request to wikipedia for the wiki page of george washington and collects the html page from the response. On 'end' of the responses readstream it resolves the html page. The function works just fine)
// utils.js
function requestWikiPage() {
const reqOpts = {
hostname : 'en.wikipedia.org',
port : 443,
path : '/wiki/George_Washington',
method : "GET"
}
return new Promise(resolve => {
let req = https.request(reqOpts, (res) => {
let resBody = "";
res.setEncoding('utf-8');
res.on('data', (chunk) => {
resBody += chunk;
});
res.on('end', () => {
resolve(resBody);
});
});
req.on('err', (err) => {
console.log(err);
});
req.end();
});
}
module.exports.requestWikiPage = requestWikiPage;
Mocha code: (The 'resBody' variable is a string, containing a html page, where '' stays on the index of 0. In the assertion I test it for 1 to create an error message)
const utils = require('./utils');
var assert = require('assert');
describe('Async functions', function() {
it('it should return a html page', (done) => {
utils.requestWikiPage().then(resBody => {
assert.equal(resBody.indexOf('<!DOCTYPE html>'), 1);
done();
});
});
});
So I dont understand why do I get that long error message just because I expect to be not on the 0 index than on the first? (Actually I get that error message whith every function not just with this)
How can I set up mocha that it gives me a more minimal and intuitive error message.
Thanks a million for your answers
You need to properly reject the promise in #requestWikiPage if it doesn't resolve or there is an error, and then handle that rejection in your test. The following changes will likely solve the issue in your question (i.e. having mocha correctly handle a failed test without all the extra output), but the next step would obviously be getting your test to pass.
Notice we add the reject callback to our new Promise() and instead of console.log(err); below in your req.on('error'... callback, we now use reject as our error callback.
// utils.js
function requestWikiPage() {
const reqOpts = {
hostname : 'en.wikipedia.org',
port : 443,
path : '/wiki/George_Washington',
method : "GET"
}
return new Promise((resolve, reject) => {
let req = https.request(reqOpts, (res) => {
let resBody = "";
res.setEncoding('utf-8');
res.on('data', (chunk) => {
resBody += chunk;
});
res.on('end', () => {
resolve(resBody);
});
});
req.on('err', reject);
req.end();
});
}
module.exports.requestWikiPage = requestWikiPage;
And now handle if the promise is rejected via a catch block by using done as the catch callback (which would effectively pass the error to done which mocha requires).
const utils = require('./utils');
var assert = require('assert');
describe('Async functions', function() {
it('it should return a html page', (done) => {
utils.requestWikiPage().then(resBody => {
assert.equal(resBody.indexOf('<!DOCTYPE html>'), 1);
done();
}).catch(done);
});
});