I'm trying to test if my Http Request method throw an error, but I always got: Unhandled promise rejection.
This is my test:
it('it should get the first page of all offers with limit 20 without a cache system', (done) => {
const httpRequestConnector = new HttpRequestConnector(apiConfigs);
const queryArgs: any = {
page: 1,
limit: 20,
};
const functionThatThrows = () => {
httpRequestConnector.offersFindAll(queryArgs, 'admin').then((res) => {
res.should.have.property('status');
res.status.should.equal(200);
res.should.have.property('body');
res.body.should.have.property('request');
res.body.request.should.have.property('page');
res.body.request.page.should.equal('1');
res.body.request.should.have.property('limit');
res.body.request.limit.should.equal('20');
res.body.should.have.property('response');
res.body.response.should.have.property('data');
res.body.response.data.should.have.property('data');
Object.keys(res.body.response.data.data).length.should.equal(20);
}).catch((err) => {
throw err;
});
};
expect(functionThatThrows).to.throw();
done();
});
This is my methods (where the "Offeree" will cause an error):
...
private query(url: string, send: any): Promise<any> {
const httpRequestService: HttpRequestInterface = new HttpRequestService();
return httpRequestService.post({
url,
send,
});
}
offersFindAll(args: any, apiDefinition: string): Promise<any> {
(new GuardAgainstNullValues())
.guard(apiDefinition);
const queryArgs = args || {};
const target: string = (apiDefinition === 'admin') ? 'Offeree' : 'Affiliate_Offer';
const method: string = 'findAll';
const apiInfos: any = this.getApiInfos(apiDefinition);
const url: string = apiInfos.api + '?api_key=' + apiInfos.api_key + '&Target=' + target + '&Method=' + method;
if (queryArgs && 'limit' in queryArgs) {
queryArgs.limit = args.limit;
} else {
queryArgs.limit = 1000;
}
return new Promise((fulfill, reject) => {
return this.query(url, queryArgs)
.then((res) => {
if (res.body.response.status === -1) {
throw new RequestStatusException('Cannot get offers');
}
fulfill(res);
})
.catch((err) => {
reject(err);
});
});
}
...
And this is my POST method from my HttpRequestService:
class HttpRequestService implements HttpRequestInterface{
private engine: SuperAgentStatic;
constructor() {
this.engine = request; // Superagent
}
get({ url, query }: { url: string, query?: any }): Promise<any>{
return new Promise((fulfill: any, reject: any) => {
this.engine
.get(url)
.query(query)
.end((err: ResponseError, res: Response) => {
if (err) {
reject(err);
}
fulfill(res);
});
});
}
post({ url, send }: { url: string, send?: any }): Promise<any>{
return new Promise((fulfill: any, reject: any) => {
this.engine
.post(url)
.send(qs.stringify(send))
.end((err: ResponseError, res: Response) => {
if (err) {
reject(err);
}
fulfill(res);
});
});
}
};
I wrapped my offersFindAll request with a promise to handle if (res.body.response.status === -1) { to throw an error instead of throwing it anywhere i use this method.
I'm trying to expect the function to throw here in my mocha test: expect(functionThatThrows).to.throw();
But i always got a (node:7485) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): RequestStatusException: Cannot get offers which is the good exception, but I can't handle the promise correctly.
I try to only return this.query without wrapping it in a promise, but does the same.
How can I structure this correctly to test if it throws?
Thank you very much for your help
In your method offersFindAll():
return new Promise((fulfill, reject) => {
return this.query(url, queryArgs)
.then((res) => {
if (res.body.response.status === -1) {
throw new RequestStatusException('Cannot get offers');
}
fulfill(res);
})
.catch((err) => {
reject(err);
});
});
the exception cannot be caught by the catch clause. It's better to write so:
return new Promise((fulfill, reject) => {
return this.query(url, queryArgs)
.then((res) => {
if (res.body.response.status === -1) {
reject('Cannot get offers');
}
fulfill(res);
})
.catch((err) => {
reject(err);
});
});
Meanwhile, the stacktrace of the errors can be found using:
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at:', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
Related
How can be resolve executed in multiple function.
As I have multiple promise function and each function contain resolve message but don't how to print this on postman
If there is single function with promise then resolve message easily get executed but what if there is function of function then how can it be possible ?
Is this possible way to return resolve or reject message from one function to another?
As I am writing to pass resolve message in postman whenever my task is completed or reject message when there is some error
But after after writing return it still not returning the resolve message or reject message inside Postman
any idea how this can be resolve?
async function readFile(filePath) {}
async function getAllFile(filePath) {
const paths = await readFile(filePath);
}
async function filterFiles(filePath) {
const paths = await getAllFile(filePath);
}
function addDocument(data){
return new Promise((resolve, reject) => {
Document.create({
name: data.name,
},
}).then(function (filePath) {
filterFiles(filePath);
let msg = "Document created Succesfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
});
}
function updateDoc(data){
return new Promise((resolve, reject) => {
Document.update({
name: data.name,
}
where: {
product_id: data,
},
})
}).then(function (filePath) {
getAllFile(filePath);
let msg = "Updated Successfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
}
function findDoc(data){
return new Promise((resolve, reject) => {
Document.findAll(
{
raw:true,
},
{
name: data.name,
}
where: {
product_id: data,
},
})
}).then(function (product) {
if(product.length===0){
addDocument(product);
let msg="task completed";
return resolve(msg,product);
else{
return resolve(updateDoc(product));
}
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
}
function findDoc(data){
return new Promise((resolve, reject) => {
Document.findAll(
where: {
product_id: data.id,
},
})
}).then(function (product) {
findDoc(product);
let msg="task completed";
return resolve(msg,product);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
}
How can i get resolve message in postman
It's hard for me to test your codes but it's quite possible to return resolve, reject messages in the response object.
If you want to pass a reject message through 3 promise for example and return a response you need use try, catch blocks, you can check this example:
// index.js
const express = require('express')
const app = express()
const port = 3000
const responder1 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
const responder2 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
const responder3 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
app.use('/', async (req, res) => {
let result;
try {
const error = new Error("This is a error message.");
result = await responder1(error, null);
} catch (error1) {
try {
await responder2(error1, null);
} catch (error2) {
try {
await responder3(error2, null)
} catch (error3) {
res.send({
success: 0,
message: error3.message
});
return;
}
}
}
res.send({
success: 0,
message: result
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
And if you want to pass resolve message:
const express = require('express')
const app = express()
const port = 3000
const responder1 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
const responder2 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
const responder3 = (error, message) => {
return new Promise((resolve, reject) => {
if (error) {
reject(error);
return;
}
resolve(message);
});
};
app.use('/', async (req, res) => {
let result = await responder3(null, await responder2(null, await responder1(null, "This is a test message.")));
res.send({
success: 0,
message: result
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
i've some doubt on promise:
this is my api functions using axios:
const _get = (url: string) => axios
.get(url)
.then((response: { data: responseData }) => {
if (response) {
console.log(response)
const { data, status, message } = response.data;
if (status) {
return data
} else {
throw new Error(message);
}
}
})
//notification is an antd component to show a toast with the error
.catch((error: Error) => notification.error({ message: 'Error', description: error.message }));
export const doStuff = (id: number) =>_get('/api/do/${id}');
When i call the api in case of error the then() is called
const callDoStuff = (id: number) => {
doStuff(id).then(() => {
//called also if doStuff catch() is resolved
notification.success({ message: 'Success', description: 'Template deleted!' });
});
};
so in catch block if i return something is considered resolved and so the outer function then() is called? in this case the only way is to keep the propagation of the error throwing an exception in the catch?
Thanks
possible soulution:
const _get = (url: string) => axios
.get(url)
.then((response: { data: responseData }) => {
if (response) {
console.log(response)
const { data, status, message } = response.data;
if (status) {
return data
} else {
throw new Error(message);
}
}
})
using specific catcher for then() error
const callDoStuff = (id: number) => {
doStuff(id)
.then((response) => {// success handler}, e=>{// specific error thrown by the inner then })})
.catch(e=>{//axios error })
using generic catcher for errors
const callDoStuff = (id: number) => {
doStuff(id)
.then((response) => { //success handler })
.catch(e=>{ // generic error handler })
so in catch block if i return something is considered resolved and so the outer function then() is called?
Yes.
in this case the only way is to keep the propagation of the error throwing an exception in the catch?
I would suggest not to put the .catch() inside _get. Instead, write
function callDoStuff(id: number) {
doStuff(id).then(() => {
notification.success({ message: 'Success', description: 'Template deleted!' });
}, (error: Error) => {
notification.error({ message: 'Error', description: error.message })
});
}
I am working with soap in Node typescript.
I want to return a boolean after performing a soap request to the server in the strong-soap package.
The code looks like:
public isSupplierBalance(debtorAccount: number): boolean {
let economicToken = this.token;
soap.createClient(this.WSDL, {}, function (err, client) {
let method = client['ConnectWithToken'];
let args = {
token: economicToken,
appToken: economicAPI.EconomicN1Key
};
method(args, function (err, result, envelope, soapHeader) {
if (err) {
console.log(err);
}
let session = cookieParser(client.lastResponseHeaders);
let args = {
creditorHandle: {
Number: debtorAccount
}
};
client.addHttpHeader('Cookie', session);
method = client['Creditor_GetOpenEntries'];
method(args, function (err, result, envelope, soapHeader) {
if (err) {
console.log(err);
}
console.log(result.toString());
return (typeof result.Creditor_GetOpenEntriesResult === 'undefined');
});
});
});
}
Basically I want to return if the result.Creditor_GetOpenEntriesResult contains any values of not. I have seen in the documentation of strong-soap that an async approach can be used, and I guess that should be my approach but any test towards that solution have just failed.
https://www.npmjs.com/package/strong-soap
Hope this helps. I was able to wrap it with a new Promise
async function callSOAP(options: {}, methodname: any, methodparams: any) {
let finalresult: any;
return new Promise((resolve, reject) => {
soap.createClient(url, options, async function (err: any, client: any) {
const { result, envelope, soapHeader } = await client[methodname](methodparams);
finalresult = { result, envelope, soapHeader }
// return { result, envelope, soapHeader };
if (err) {
reject(err);
}
else { resolve(finalresult) };
});
}
The calling code would look like this
result = await callSOAP(options, methodname, methodparams).then((r1) => r1);
I have one function, which returns Promise:
updatePassword(currentPassword: string, newPassword: string): Promise<void> {
return this.fireAuth.currentUser.then((user: firebase.User) => {
if (user) {
const credentials = auth.EmailAuthProvider.credential(user.email, currentPassword)
user.reauthenticateWithCredential(credentials).then(res => {
if (res) {
user.updatePassword(newPassword)
}
}).catch(err => {
throw new Error(err)
})
}
})
}
I call it inside another component:
this.userService.updatePassword(currentPassword, newPassword).then(() => {
console.log('successfully')
}).catch(err => {
console.log('error')
})
But even when updatePassword() return Error, the function call in component still console log 'successfully' from 'then`. How to properly throw an error in my case?
You also need to return your inner promise. Like this:
updatePassword(currentPassword: string, newPassword: string): Promise<void> {
return this.fireAuth.currentUser.then((user: firebase.User) => {
if (user) {
const credentials = auth.EmailAuthProvider.credential(user.email, currentPassword)
return user.reauthenticateWithCredential(credentials).then(res => {
if (res) {
user.updatePassword(newPassword)
}
}).catch(err => {
throw new Error(err)
})
}
throw new Error('USER_NOT_FOUND')
})
}
Edit:
I also added throw if you do not get user as safety net.
Refactor your function to use async/await, and you don't need to manually throw anything.
You may wish to make those return falses some sort of throw too.
async updatePassword(currentPassword: string, newPassword: string): Promise<void> {
const user = await this.fireAuth.currentUser;
if(!user) return false;
const credentials = auth.EmailAuthProvider.credential(user.email, currentPassword);
const res = await user.reauthenticateWithCredential(credentials);
if(!res) return false;
user.updatePassword(newPassword);
return true;
}
If your fireAuth call fails, then throw a Error from the updatePassword catch block.
Check the working snippet attached.
let fireAuth = (pass = false) => {
if (pass) return Promise.resolve("passed");
return Promise.reject("failed");
};
function updatePassword(shouldPass = false) {
if (!shouldPass) {
return fireAuth(false)
.then(console.log)
.catch((err) => {
console.log('err in fireauth', err)
throw new Error('OOPS')
});
}
return Promise.resolve("success");
}
let failedResult = updatePassword()
.then()
.catch((err) => console.log("failedresult error", err.toString()));
let successResult = updatePassword(true)
.then((res) => console.log("res is", res))
.catch();
I am trying to refactor this code using try-catch blocks:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
}).catch(error => console.log(error));
}
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
}).catch(error => console.log(error));
}
However I'm not getting the same result - the asynchronousity seems to be being handled differently. Here is my attempt at refactoring:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
try {
ConnectyCube.login(userCredentials, (error, user) => {
return user;
})
}
catch (error) {
console.log(error)
}
}
const createSession = () => {
try {
ConnectyCube.createSession((error, session) => {
return session.user
})
} catch (error) {
console.log(error);
}
}
Is there any particular part of what I'm wrong? Thanks.
Callback-based APIs don't readily turn into something you can use for async/await (which under the hood uses promises). You'll have to "promisify" them first (i.e. wrap them in promises).
Here's an example of what I'm trying to say:
// Promisify these callback-based APIs.
const login = userCredentials => {
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
})
})
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
})
})
// Then use them in an async function
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
}
try {
await createSession()
return login(userCredentials)
} catch (e) {
console.warn(e)
}
}
Also, async functions return promises, with the resolved value being the return value, and the rejected value being any uncaught error thrown inside. A value wrapped in a promise as return value for an async function is redundant.
If you're using Node 8+, it has a utility called promisify which accepts a callback-based API and returns a promise-returning version of it.