Promise returns wrong value - javascript

In my code I try to assign a value to json variable to return it after (because I can't return it from the anon. function).
As my function is async, because it sends requests (maybe someone knows how to make it sync? I didn't plan to make it asynchronous), I've added await before the request (https.get).
I've been trying to get value from the Promise, but it's always undefined, even though I've awaited the async function.
Here's a code:
async function get_users() {
const https = require('https');
var token = '...';
var json = undefined;
await https.get('...', (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
json = JSON.parse(data)['response']['items'];
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
return json;
}
get_users().then(function(result) {
console.log(result);
});

Return a Promise and resolve it, when the end event is called, otherwise reject it in case of an error occurred:
async function get_users() {
const https = require('https');
const token = '...';
return new Promise((resolve, reject) => {
https.get('...', resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
let json;
try {
json = JSON.parse(data)['response']['items'];
} catch (e) {
reject(e);
};
resolve(json);
});
}).on("error", err => reject(err));
});
}
get_users().then(result => console.log(result));

Please refer my below code.I had issues with getting responses from Promises too.But i finally got it to work.Here's the code:
var output;
var rp = require('request-promise-native');
var myJSONObject = {
"inputs": [{
"name": "<name>",
"value": < value >
}]
};
var orchName = 'TEST05';
postData = JSON.stringify(myJSONObject);
return networkCall(postData, orchName).then((response) => {
console.log('response is' + response)
}).catch((response) => {
console.log(`ERROR: ` + response);
});
function networkCall(postData, orchName) {
return new Promise((resolve, reject) => {
var options = {
method: 'post',
uri: '<URL>',
body: postData,
auth: {
'user': 'usr',
'pass': 'pwd'
},
json: true
};
return rp(options)
.then(body => {
var response = body;
resolve(response);
})
.catch(err => {
console.log('FAILED' + err);
reject(err);
});
});
}
This way your code can run in Synchronous Flow.If the return value is undefined,then,what might have probably happened is that the calling function would have finished executing even before the called function returns its response.But the above approach would work just fine.

Related

test http.request with options using jest

Im learning using Jest and i faced this function,
but not sure how to start testing, it has inside an http.request({}, (res) => {})
and not sure how can i mock this http.request inside the current function:
also the resolve and reject from the current promise,
in advance Thank You!
const options = {
hostname: 'myHostName'
port: 'myPort',
path: 'myPath',
method: 'GET'
};
function myRequest(options) {
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
if (res.statusCode === 200) {
let responseData = '';
res.on('data', (data) => {
responseData += data;
});
res.on('end', () => {
const response = JSON.parse(responseData);
resolve([response, true]);
});
} else {
reject(`res.message`);
}
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}

Node.JS: how to wait for a process to finish before continuing?

I am new to node and stuck with this issue. Here' the file:
I am running 'startProcess' function and I want to run 'downloadFiles' and wait until it's completed and save the files before executing any code after it.
This code always ends up running 'runVideoUploadEngine' even before the download has been completed?
const downloadAndSaveFiles = async ({ url, dir }) => {
try {
https.get(url, (res) => {
// File will be stored at this path
console.log('dir: ', dir);
var filePath = fs.createWriteStream(dir);
res.pipe(filePath);
filePath.on('finish', () => {
filePath.close();
console.log('Download Completed');
});
});
return true;
} catch (e) {
console.log(e);
throw e;
}
};
const downloadFiles = async ({ data }) => {
try {
mediaUrl = data.mediaUrl;
thumbnailUrl = data.thumbnailUrl;
const mediaExt = path.extname(mediaUrl);
const thumbExt = path.extname(thumbnailUrl);
mediaDir = `${__dirname}/temp/${'media'}${mediaExt}`;
thumbDir = `${__dirname}/temp/${'thumb'}${thumbExt}`;
await downloadAndSaveFiles({ url: mediaUrl, dir: mediaDir });
await downloadAndSaveFiles({ url: thumbnailUrl, dir: thumbDir });
return { mediaDir, thumbDir };
} catch (e) {
console.log(e);
throw e;
}
};
module.exports = {
startProcess: async ({ message }) => {
//check if message is proper
data = JSON.parse(message.Body);
//download video and thumbnail and store in temp.
console.log('starting download..');
const { mediaDir, thumbDir } = await downloadFiles({ data });
console.log('dir:- ', mediaDir, thumbDir);
pageAccessToken =
'myRandomToken';
_pageId = 'myRandomPageID';
console.log('running engine');
await runVideoUploadEngine({ pageAccessToken, _pageId, mediaDir, thumbDir });
//start videoUploadEngine
//on success: delete video/thumbnail
},
};
What am I doing wrong?
downloadAndSaveFiles returns a promise (because the function is async) but that promise doesn't "wait" for https.get or fs.createWriteStream to finish, and therefore none of the code that calls downloadAndSaveFiles can properly "wait".
If you interact with callback APIs you cannot really use async/await. You have to create the promise manually. For example:
const downloadAndSaveFiles = ({ url, dir }) => {
return new Promise((resolve, reject) => {
// TODO: Error handling
https.get(url, (res) => {
// File will be stored at this path
console.log('dir: ', dir);
var filePath = fs.createWriteStream(dir);
filePath.on('finish', () => {
filePath.close();
console.log('Download Completed');
resolve(); // resolve promise once everything is done
});
res.pipe(filePath);
});
});
};

Understanding HTTP function inside Alexa Skill-- JavaScript

I am currently learning how to connect my Amazon Lambda function (in js) to an API. I found the following code which works but I am new to javascript and APIs in general and am not sure what it is doing. Could someone explain to me what this function does and how it works? Thanks!
function httpGet() {
return new Promise(((resolve, reject) => {
var options = {
host: 'api.icndb.com',
port: 443,
path: '/jokes/random',
method: 'GET',
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
Here the response object is a node.js stream, a 'push' stream in particular. (This article does a good job of explaining push/pull streams).
const request = https.request(options, (response) => {
// Your request has been successfully made and you are
// handed a response object which is a stream, which will emit
// a 'data' event when some data is available.
response.setEncoding('utf8');
let returnData = '';
// A chunk of data has been pushed by the stream,
// append it to the final response
response.on('data', (chunk) => {
returnData += chunk;
});
// All the data has been pushed by the stream.
// 'returnData' has all the response data. Resolve the
// promise with the data.
response.on('end', () => {
resolve(JSON.parse(returnData));
});
// Stream has thrown an error.
// Reject the promise
response.on('error', (error) => {
reject(error);
});
});
request.end();
I found a better solution. Create a function to getRemoteData and/or postRemoteData.
getRemoteData (url) {
return new Promise((resolve, reject) => {
axios
.get(url)
.then(res => {
console.log(res.data);
resolve(res.data);
})
.catch(error => {
console.error(error);
});
})
},
postRemoteData (url, body) {
return new Promise((resolve, reject) => {
axios
.post(url, body)
.then(res => {
console.log(res.data);
resolve(res.data);
})
.catch(error => {
console.error(error);
});
})
},
Then use these functions in your IntentsHandlers.
//Get
const url = "https://anydir.com"
let speakOutput = "No data";
await logic.getRemoteData(url)
.then((data) => {
speakOutput = data.results.toString();
})
//Post
const url = "https://anydir.com"
let speakOutput = "No data";
await logic.getRemoteData(url, {param1:valueParam1,param2:valueParam2})
.then((data) => {
speakOutput = data.results.toString();
})
Example.
const NumberCharactersIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'NumberCharactersIntent';
},
async handle(handlerInput) {
const url = "https://rickandmortyapi.com/api/character"
let speakOutput = "No data";
await logic.getRemoteData(url)
.then((data) => {
speakOutput = `There are ${data.results.length.toString()} in the Rick and Morty serie`
})
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};

Function with fetch returns undefined instead an array (React Native)

I have a file with some functions:
const API = {
async getComments() {
var data = [];
var url = 'http://url.com/wp-json/wp/v2/comments';
const serviceResponse = await fetch(
url,
)
.then((serviceResponse) => {
return serviceResponse.json();
} )
.catch((error) => console.warn("fetch error:", error))
.then((serviceResponse) => {
for (i in serviceResponse) {
data.push({
"key": serviceResponse[i]['id'].toString(),
"name": serviceResponse[i]['author_name'],
"content": serviceResponse[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": serviceResponse[i]['author_avatar_urls']['96'],
"date": serviceResponse[i]['date'].replace('T', ' ')
});
}
global.comments = data;
return data;
});
}
}
export { API as default }
In another file I include the file, and make the call:
var comments = await API.getComments(key);
console.log (comments);
But I receive undefined, I tried to create a function with bind:
this.newGetComments = API.getComments.bind(this); with the same result. I used a global variable, but I want to remove the globals vars.
/* Few suggestions;
1. you are not returning anything from the getComments method. Please return fetch(url) response.
2. you should return something from the catch block to handle the error.
*/
const API = {
async getComments() {
var url = 'http://url.com/wp-json/wp/v2/comments';
var response = await fetch(url)
.then(serviceResponse => {
return serviceResponse.json();
})
.then(serviceResponse => {
let data = [];
// rest of your code.
return { success: true, data };
})
.catch(error => {
console.warn('fetch error:', error);
return { success: false, error };
});
return response
},
};
var comments = await API.getComments(key);
if (comments.success) {
// handle the success case comments.data
} else {
// handle the Error case comments.error
}
console.log(comments);
An async function always returns a promise as you aren't returning anything from the getComments methods, the function automatically resolves and returns undefined(Promise.resolve(undefined)). You need to return serviceResponse from the getComments method to get the fetch api's response.
You can try something like below:
async componentDidMount() {
let data = [];
const result = await this.getComments();
const jsonData = await result.json();
console.log('Result ==> ', jsonData.serviceResponse);
jsonData.serviceResponse.map(data =>
data.push({
"key": data['id'].toString(),
"name": data[i]['author_name'],
"content": data[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": data[i]['author_avatar_urls']['96'],
"date": data[i]['date'].replace('T', ' ')
})
);
console.log('Data ==> ', data);
}
async getComments() {
const result = await fetch('http://url.com/wp-json/wp/v2/comments', {method: 'GET'});
return result;
}

Node.js - Mock result of a promise

I want to mock the result of a function within a node module so that i can run assertions.
Considering the following node module:
const doPostRequest = require('./doPostRequest.js').doPostRequest;
const normalizeSucessResult = require('./normalizer.js').normalizeSucessResult;
const normalizeErrorResult = require('./normalizer.js').normalizeErrorResult;
exports.doPost = (params, postData) => {
return doPostRequest(params, postData).then((res) => {
const normalizedSuccessResult = normalizeSucessResult(res);
return normalizedSuccessResult;
}).catch((err) => {
const normalizedErrorResult = normalizeErrorResult(err);
return normalizedErrorResult;
})
}
The function doPostRequest returns a promise. How can i fake the return value of this promise so that i can assert if normalizeSucessResult has been called?
So for i have tried:
const normalizeSucessResult = require('./normalizer.js');
const doPostRequest = require('./doPostRequests.js');
const doPost = require('./doPost.js');
it('runs a happy flow scenario', async () => {
let normalizeSucessResultStub = sinon.stub(normalizeSucessResult, 'normalizeSucessResult');
let postData = { body: 'Lorum ipsum' };
let params = { host: 'someUrl', port: 433, method: 'POST', path: '/' };
sinon.stub(doPostRequest, 'doPostRequest').resolves("some response data"); //Fake response from doPostRequest
return doPost.doPost(params, postData).then((res) => { //res should be equal to some response data
expect(normalizeSucessResultStub).to.have.been.calledOnce;
expect(normalizeSucessResultStub).to.have.been.with("some response data");
});
});
The doPostRequest module looks like this:
const https = require('https')
module.exports.doPostRequest = function (params, postData) {
return new Promise((resolve, reject) => {
const req = https.request(params, (res) => {
let body = []
res.on('data', (chunk) => {
body.push(chunk)
})
res.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString())
} catch (e) {
reject(e)
}
resolve(body)
})
})
req.on('error', (err) => {
reject(err)
})
if (postData) {
req.write(JSON.stringify(postData))
}
req.end()
})
}
You can use Promise.resolve to return a promise with any given value.
Promise.resolve(“hello world”);
For stub your func you need to do like this
sinon.stub({doPostRequest}, 'doPostRequest').resolves("some response data")
Okay, i figured it out. The function doPostRequest was loaded using require, on the top of the file using const doPostRequest = require('./doPostRequest.js').doPostRequest;
In order to mock the data that comes back from a function that is loaded using require i had to use a node module called mock-require. There are more modules that can take care of this (proxyquire is a populair one) but i picked mock-require (i did not have a specific reason for choosing mock-require).
For anyone else that is stuck with a similar problem, try mock-require to mock the respose from files that are loaded using require.

Categories