Create an Error object with particular properties in unit testings - javascript

I'm trying to implement unit test for the following piece of my code
try {
return await request.post(options);
} catch (err) {
if (err.statusCode === 401) {
log.info('Not authenticated. Refreshing token...');
const tokenResponse =
await Janus.refreshToken(graph.username, graph.password, graph.host, graph.port);
const token = tokenResponse.body.token;
graph.token = token;
return gremlinQuery(graph, query);
}
log.error(`Gremlin script didn't pass : ${err}`);
}
In order to test the lines contained in the catch part, I stub the post function:
stubPost.callsFake(() => Promise.reject(new Error()));
How can I implement an error with the property statusCode? Error constructor is waiting for a string as an input. Can't I pass it an object or something like that?

One way to do this could be as below
MyApiError = function(data) {
this.code = data.code;
this.message = data.message
}
MyApiError.prototype = Error.prototype;
var e = new MyApiError({code: 33, message: 'test'});
e.code; // 33
e.message; // 'test'

Related

React: TypeError Cannot read properties of undefined (reading '0')

I am working on a React App, and i'm trying to get some data using an axios GET request from my node backend.
the Api Endpoint i'm currently using that regard this problem is the following:
// NodeJS Backend
app.get('/v1/companys/user/:user_uuid', verify, (req, res) => { // GET - Company by User UUID
const selectQuery = 'SELECT * FROM companys WHERE uuid = (SELECT company_uuid FROM users WHERE uuid = ?)';
connection.query(selectQuery, [req.params.user_uuid], (err, results) => {
if(err) {
res.send(err)
} else if (results.length === 0) {
res.json({status: 404, message: 'Company not found'})
} else {
res.json({data: results})
}
});
});
This is my Front End:
// ReactJS FrontEnd
const companyLogo = userCompany ? userCompany.logo_url : null;
console.log(userCompany);
useEffect(() => {
const getUserCompany = async () => {
try {
await axios.get(process.env.REACT_APP_API_URL + 'companys/user/' + userUuid).then((response) => {
console.log("response "+ response);
let res = response.data.data[0];
console.log(res);
setUserCompany(res);
});
} catch (error) {
console.log(error);
}
};
getUserCompany();
}, [userUuid]);
There app works fine, but on the console the following error appear:
The object below the error is in fact the thing that i need (companyLogo)
I was wondering if someone know what am I doing wrong on my frontend to fix the TypeError.
Thanks for the help!
If you use optional chaining (?.) to catch possible null/undefined values, you'll most likely fix the issue.
So like this: let res = response.data.data?.[0];

Why doesn't sawtooth allow me to raise exceptions?

When I want to declare an error in my handler, it causes an infinite loop in my processor which displays in the console :
{ InvalidTransaction: InvalidTransaction: The campaign does not exist!
at VoteHandler.apply (/app/handler.js:79:19)
at <anonymous> name: 'InvalidTransaction' }
"The campaign does not exist!" being my error message.
Example :
const { TransactionHandler } = require('sawtooth-sdk/processor/handler');
const { InvalidTransaction } = require('sawtooth-sdk/processor/exceptions');
class VoteHandler extends TransactionHandler {
constructor() {
super(FAMILY_NAME, ['1.0'], [NAMESPACE]);
}
// apply function - execution starts here when a transaction reaches the validator for this transaction processsor
async apply(batches, context) {
var request = JSON.parse(decoder.decode(batches.payload));
let campaign = {};
let address = NAMESPACE + hash(request.idCampaign).substring(0, 14) + hash(batches.header.signerPublicKey).substring(0, 50);
switch(request.type){
case "INITIALIZE":
await context.getState([address]).then((addressValues) => {
if(addressValues[address].length == 0){
console.log("Create the campaign!");
}else{
throw new InvalidTransaction("The campaign already exists!");
}
}).catch((err) => {
throw new InvalidTransaction("Error when initializing the campaign!");
});
break;
case "NEW_VOTE":
await context.getState([address]).then((addressValues) => {
if(addressValues[address].length == 0){
throw new InvalidTransaction("The campaign doesn't exist, you can't vote!");
}else{
console.log("Vote taken into account!");
}
}).catch((err) => {
throw new InvalidTransaction("The campaign does not exist!");
});
break;
default:
throw new InvalidTransaction("The type of action is not defined!");
}
console.log('==============State==============');
console.log(campaign);
console.log('=============Message=============');
console.log(request);
console.log('=================================');
if(Object.keys(campaign).length !== 0){
return context.setState({
[address]: encoder.encode(JSON.stringify(campaign))
});
}
}
}
I develop my processor in JS and I could see code examples in java, js, python, ... They always do the same thing, that is to say simply declare the exception by importing it from the sawtooth-sdk package (sawtooth-sdk/processor/exceptions).
Java :
throw new InvalidTransactionException("Version does not match");
LINK : Daml Transaction Java
Python :
raise InvalidTransaction('Invalid action: Take requires an existing game')
LINK : Sawtooth xo pyton
JS :
throw new InternalError('State Error!')
LINK : Simple Wallet JS
I also tried to get the exceptions from the package #restroom-mw/sawtooth-sdk/ but the error is still there.
IMAGE : Import exceptions
Normally my error report should return an error code with my error message to my client.

How to get error line using Nestjs avoiding duplicate code

I made a controller on nestjs as below.
#Post()
public async addConfig(#Res() res, #Body() createConfigDto: CreateConfigDto) {
let config = null;
try {
config = await this.configService.create(createConfigDto);
} catch (err) {
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
status: 500,
message: 'Error: Config not created!',
});
}
if (!config) {
return res.status(HttpStatus.NOT_FOUND).json({
status: 404,
message: 'Not Found',
});
}
return res.status(HttpStatus.OK).json({
message: 'Config has been created successfully',
config,
});
}
And there is a service in other file.
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
do something 1
do something 2
do something 3
return result;
}
If an internal server error occurs among "do somehting 1,2 or 3" when I request to this api, it will gives me response 500.
But I want to know in which line the error happend.
Therefore I made catch line function.
const getStackTrace = () => {
const obj = {};
Error.captureStackTrace(obj, getStackTrace);
return obj.stack;
};
And I wrap the code with this function, like this
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
try{
do something 1
}catch(error){
console.log(error)
getTrace()
}
try{
do something 2
}catch(error){
console.log(error)
getTrace()
}
try{
do something 3
}catch(error){
console.log(error)
getTrace()
}
return result;
}
But the problem is the service code will grow a lot with this trace function.
I want to know whether there is more efficient way avoiding duplicate code using nestJs for this case.
I think interceptor or execption filter help this.
But I don't know how to code for this case , since I 'm about to start using nestjs.
Thank you for reading my question.

Retrieve Result from Hyperledger Fabric Transaction

I submitted a transaction to Hyperledger Fabric, but I'd like to get object created by this.
The object that I get from this is Undefined.
Obs: The transaction is successfully created in Hyperledger Fabric.
async submit(resource, method) {
try{
this.businessNetworkDefinition = await this.bizNetworkConnection.connect(cardname);
if (!this.businessNetworkDefinition) {
console.log("Error in network connection");
throw "Error in network connection";
}
let factory = this.businessNetworkDefinition.getFactory();
let transaction = factory.newTransaction(NS, method);
Object.assign(transaction, resource)
return await this.bizNetworkConnection.submitTransaction(transaction);
}catch(error){
console.log(error);
throw error;
}
}
Currently the submitTransaction function is not returning anything. It is a bug or working as intended.
To go into more detail: When you delve through the source code of the composer you will finally get to the following code in composer-connector-hlfv1.
invokeChainCode(securityContext, functionName, args, options) {
const method = 'invokeChainCode';
LOG.entry(method, securityContext, functionName, args, options);
if (!this.businessNetworkIdentifier) {
return Promise.reject(new Error('No business network has been specified for this connection'));
}
// Check that a valid security context has been specified.
HLFUtil.securityCheck(securityContext);
// Validate all the arguments.
if (!functionName) {
return Promise.reject(new Error('functionName not specified'));
} else if (!Array.isArray(args)) {
return Promise.reject(new Error('args not specified'));
}
try {
args.forEach((arg) => {
if (typeof arg !== 'string') {
throw new Error('invalid arg specified: ' + arg);
}
});
} catch(error) {
return Promise.reject(error);
}
let txId = this._validateTxId(options);
let eventHandler;
// initialize the channel if it hasn't been initialized already otherwise verification will fail.
LOG.debug(method, 'loading channel configuration');
return this._initializeChannel()
.then(() => {
// check the event hubs and reconnect if possible. Do it here as the connection attempts are asynchronous
this._checkEventhubs();
// Submit the transaction to the endorsers.
const request = {
chaincodeId: this.businessNetworkIdentifier,
txId: txId,
fcn: functionName,
args: args
};
return this.channel.sendTransactionProposal(request); // node sdk will target all peers on the channel that are endorsingPeer
})
.then((results) => {
// Validate the endorsement results.
LOG.debug(method, `Received ${results.length} result(s) from invoking the composer runtime chaincode`, results);
const proposalResponses = results[0];
let {validResponses} = this._validatePeerResponses(proposalResponses, true);
// Submit the endorsed transaction to the primary orderers.
const proposal = results[1];
const header = results[2];
// check that we have a Chaincode listener setup and ready.
this._checkCCListener();
eventHandler = HLFConnection.createTxEventHandler(this.eventHubs, txId.getTransactionID(), this.commitTimeout);
eventHandler.startListening();
return this.channel.sendTransaction({
proposalResponses: validResponses,
proposal: proposal,
header: header
});
})
.then((response) => {
// If the transaction was successful, wait for it to be committed.
LOG.debug(method, 'Received response from orderer', response);
if (response.status !== 'SUCCESS') {
eventHandler.cancelListening();
throw new Error(`Failed to send peer responses for transaction '${txId.getTransactionID()}' to orderer. Response status '${response.status}'`);
}
return eventHandler.waitForEvents();
})
.then(() => {
LOG.exit(method);
})
.catch((error) => {
const newError = new Error('Error trying invoke business network. ' + error);
LOG.error(method, newError);
throw newError;
});
}
As you can see at the end, all that is happening is waiting for Events and Log.exit which return nothing. So currently you have to get your transaction result in another way.
The only way I could get something from my chaincode is through events. There's native interface that might be able to query for transaction data or something like this, but i haven't looked into it yet.

Wait for AWS SNS publish callback to return a value to calling method

I am attempting to send a text message when a user requests to reset their password. I would like to wait for the message to be sent to alert the user if it was successful or not. I am currently attempting to do it as follows:
async function sendResetPasswordTextMessage(req, res) {
let result = {};
let phoneNumber = req.body.phoneNumber;
if (phoneNumber === undefined) {
return sendInvalidParametersMessage(res);
}
phoneNumber = phoneNumber.toString();
const userProfile = await models.UserProfile.findOne({
where: {
phoneNumber: phoneNumber
}
});
************************** RELEVANT CODE TO ISSUE *************************
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
const sent = await AWSSNSClient.sendMessage(message, phoneNumber);
if (!sent) {
result.error = setTitleAndMessage("Error", "An error occurred");
} else {
result.success = setTitleAndMessage("Success", "Message sent");
}
}
return res.send(result);
***************************************************************************
}
In my other class AWSSNSClient, I have the following sendMessage function:
function sendMessage(message, phoneNumber) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
let sent = false;
sns.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
sent = true;
}
});
return sent;
}
I cannot figure out how to make sendMessage wait for sns.publish to return before it returns itself. I have tried making it an async method and adding await on sns.publish, but the function still returns before sent gets set to true.
I know that the messages are sending without error because I am receiving them and no console logs are printed.
Stumbled on this one via Google trying to figure this out myself today - short answer that I am now using:
You can now do this with Async/Await — and Call the AWS service (SNS for example) with a .promise() extension to tell aws-sdk to use the promise-ified version of that service function (SNS) instead of the call back based version.
The only caveat here is the containing function must ALSO be async to utilize the await syntax.
For example:
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("SNS Push Failed:");
console.log(err.stack);
return;
}
console.log('SNS push suceeded: ' + data);
return data;
}).promise();
The important part is the .promise() on the end there. Full docs on using aws-sdk in an async / promise based manner can be found here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html
In order to run another aws-sdk task you would similarly add await and the .promise() extension to that function (assuming that is available).
For anyone who runs into this thread and is actually looking to simply push multiple aws-sdk promises to an array and wait for that WHOLE array to finish (without regard to which promise executes first) I ended up with something like this:
let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return;
}
console.log('Search push suceeded: ' + data);
return data;
}).promise();
snsPromises.push(snsResult)
await Promise.all(snsPromises)
Hope that helps someone that randomly stumbles on this via google like I did!
stackdave will that actually wait?
Necevil "Search push suceeded will get logged twice" because you're mixing calling operations by passing a callback and using promises. You should only use one method of getting the result
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn}).promise()
will do the trick
You can simply use callbacks for that. Modify your sendMessge like this
function sendMessage(message, phoneNumber, cb) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
sns.publish(params, cb);
}
then on your main file you can supply callback like this
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
if (err) {
result.error = setTitleAndMessage("Error", "An error occurred");
}
else {
result.success = setTitleAndMessage("Success", "Message sent");
}
res.send(result);
});
}
Here the right updated API, August 2018, Necevil answer send the sms twice.
// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
accessKeyId: process.env.AMAZON_SMS_ID,
secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});
// parameters
let params = {
Message: contentSMS, // here your sms
PhoneNumber: mobile, // here the cellphone
};
const snsResult = await sns.publish(params, async (err, data) => {
if (err) {
console.log("ERROR", err.stack);
}
console.log('SNS ok: ' , JSON.stringify (data));
});
If you're having issues with duplicate SNS messages being sent, I fixed this issue by utilizing examples from AWS:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
By utilizing a traditional .then() I was able to squash the duplicate message bug mentioned in comments above.
You can create a async function what use the promise method
async function sendMessage(message, phoneNumber){
const params = {
Message: message,
PhoneNumber: phoneNumber
};
return new Promise((resolve, reject) => {
SNS.publish(params, (err, data) => {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return reject(err);
} else {
console.log('Search push suceeded:' + phoneNumber);
return resolve(data);
}
})
});
}
and then you can call
var s= await sendMessage(message,phoneNumber);

Categories

Resources