Please I am trying to concatenate string result to a variable in an express router but it returns an empty string - arrays

I am trying to iterate through the array get the value and search the database, then concatenate the database result to the string translation
app.get('/translate',function(req,res) {
let translate = '';
['hello','love'].forEach(async (word) => {
let trans = await
NaijaLang.find({"engword": word, "naijalang": "yoruba"});
translate +=" " + trans[0].translation;
//Returns values
console.log(translate)
});
//Returns Empty String;
console.log(translate)
res.send(translate);
});

Because you do some async stuff there, but you send the value synchronously. Basically, this code will run in this order:
run let translate='';
run ['hello','love'].forEach(...)
run await NaijaLang.find(...) asynchronously for word=hello
run await NaijaLang.find(...) asynchronously for word=love
run console.log(translate) and res.send(translate);
resolve the value of await NaijaLang.find(...) -> this is the time when the translate is updated for the first time (either for word=hello or word=love. Whatever finishes earlier)
resolve the value of second call await NaijaLang.find(...) -> this is the time when the translate is updated for the second time. But the value was already send in the 5th step.
You can find more detailed explanation here: https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795
And you can also find there how to fix it. You can use the for-of loop instead of forEach:
app.get('/translate',function(req,res){
let translate='';
for (let word of ['hello','love']) {
let trans=await NaijaLang.find({"engword":word,"naijalang":"yoruba"});
translate+=" " + trans[0].translation;
//Returns values
console.log(translate)
}
//Returns Empty String;
console.log(translate)
res.send(translate);
});
This time, the code will execute as you probably want. First, the find method will be called for word=hello, then, after the execution is finished, the find method will be called for word=love and finally after both calls are finished, the res.send will be called.

Related

Looping through REST API calls improperly breaks at first iteration or last iteration

I am trying to send a REST API call to retrieve a lot of data. Now this data is returned in JSON format and is limited to 2000 records each call. However, if there are more than 2000 records then there is a key called nextRecordsUrl with a link to an endPoint with the next 2000 records.
And this pattern continues until there are less than 2000 records in a single call and then nextRecordsUrl is undefined.
I have this loop that essentially pushes the data to an array and then calls the endpoint listed in the nextRecordsUrl key.
do {
for (var i in arrLeads.records) {
let data = arrLeads.records[i];
let createDate = new GMT(data.CreatedDate, "dd-MM-YYYY");
let fAssocDate = new GMT(data['First_Campaign_assoc_date__c'],"dd-MM-YYYY");
let lAssocDate = new GMT(data['Last_Campaign_assoc_date__c'], "dd-MM-YYYY");
let convDate = new GMT(data.ConvertedDate, "dd-MM-YYYY");
leads.push([data.FirstName, data.LastName, data.Id, data.Email, data.Title, data['hs_contact_id__c'], createDate, data.Company, data.OwnerId, data.Country, data['Region_by_manager__c'], data.Status, data.Industry, data['Reason_for_Disqualifying_Nurture__c'], data['Reason_for_Disqualifying_Dead__c'], data['Lead_Type__c'], data['First_Campaign_Name__c'], data['First_CampaignType__c'], fAssocDate, data['Last_Campaign_Name__c'], lAssocDate, data['Last_Campaign_Type__c'], convDate, data.ConvertedAccountId, data.ConvertedContactId, data.ConvertedOpportunityId]);
}
var arrLeads = getQueryWithFullEndPoint(arrLeads.nextRecordsUrl);
} while (arrLeads.nextRecordsUrl != null && arrLeads.nextRecordsUrl != undefined);
I used to use the regular while loop, but it caused obvious problems in that it wouldn't run at all if the initial call had an empty nextRecordsUrl field.
But this also has an issue. While the first iteration works well, the last one does not because it makes the call on the next iteration before the loop checks the nextRecordsUrl field.
So essentially, it will loop through all the records normally. But when it gets to the last one, it has already run the last endPoint and will break the loop, because now the 'nextRecordsUrl key is empty. So the last iteration will be ignored.
I thought of moving the call to after the check, right after the do {, but that will cause problems for the first iteration.
I also thought about duplicating the for loop after the do, but I prefer a cleaner solution that doesn't involve duplicating code.
So how do I write this code in a way that takes into account the first iteration, even if there no second iteration and the last iteration, where it has records but has an empty nextRecordsUrl, without having to double up the code?
I actually managed to solve this with a small tweak in the code.
My issue is that I getting the next batch before I could test the original, and so I was always 1 batch short.
The solutions was actually to define a variable at the beginning of each loop arrLeadsNext = arrLeads.nextRecordsUrl;
and have the while statement check this variable.
So it looks like this:
do {
var arrLeadsNext = arrLeads.nextRecordsUrl;
for (var i in arrLeads.records) {
let data = arrLeads.records[i];
let createDate = new GMT(data.CreatedDate, "dd-MM-YYYY").process();
let fAssocDate = new GMT(data['First_Campaign_assoc_date__c'], "dd-MM-YYYY").process();
let lAssocDate = new GMT(data['Last_Campaign_assoc_date__c'], "dd-MM-YYYY").process();
let convDate = new GMT(data.ConvertedDate, "dd-MM-YYYY").process();
leads.push([data.FirstName, data.LastName, data.Id, data.Email, data.Title, data['hs_contact_id__c'], createDate, data.Company, data.OwnerId, data.Country, data['Region_by_manager__c'], data.Status, data.Industry, data['Reason_for_Disqualifying_Nurture__c'], data['Reason_for_Disqualifying_Dead__c'], data['Lead_Type__c'], data['First_Campaign_Name__c'], data['First_CampaignType__c'], fAssocDate, data['Last_Campaign_Name__c'], lAssocDate, data['Last_Campaign_Type__c'], convDate, data.ConvertedAccountId, data.ConvertedContactId, data.ConvertedOpportunityId]);
}
var arrLeads = (arrLeadsNext != null) ? getQueryWithFullEndPoint(arrLeadsNext) : '';
} while (arrLeadsNext != null && arrLeadsNext != undefined);
So the check at the end hasn't been changed by the next API call for the next batch as it will only change once the next iteration of the loop begins.

javascript evaluation failed- karate

I am trying to call an API in second feature file , passing arguments from first feature file . These has to be passed as a param for second API
* def activeDetails =
"""
function(times){
for(i=0;i<=times;i++){
karate.log('Run test round: '+(i+1));
karate.call('getActiveRouteDetails.feature', { token: token, currentPage: i });
}
java.lang.Thread.sleep(1*1000);
}
"""
* call activeDetails totalPages
In my second feature , I am able to print the values passed , Getting error while passing it as a param 'no step-definition method match found for: param pageNumber'
And print currentPage
And print token
And param pageNumber = '#currentPage'
And param token = token
Watch the white space around the = sign. Normally if you use IDE support you can avoid these issues. You seem to have an extra space after pageNumber.
So make this change:
And param pageNumber = currentPage
I request you to please read the docs and examples. You are still un-necessarily making 2 calls. And over complicating your test.

How to store array values in an environment variable in Postman

I am using a postman to automate apis.
Now I am using following request , lets say :-
{
"customerId": "{{currentClientId}}"
}
Where clientid is a dynamic variable whose value is substituted dynamically as 1 , 2, 3,4 so on..
I call this request multiple times using setNextRequest call in this eg lets say 10.This is being done using a counter variable. I am initialising the counter in my previous request to 0 and using for loop with value as counter as 10 calling the request 10 times.There is no response in body just successful http code 204.
I want to store all these clientids coming in request into an environment Client array variable so I wrote a following pre-request script:-
counter = pm.environment.get("counter");
ClientArray = pm.environment.get("ClientArray");
ClientArray.push(pm.environment.get("currentClientId"));
pm.environment.set("ClientArray",ClientArray);
In Test Script, wrote following code :-
counter = pm.environment.get("counter");
if(counter<=10) {
console.log("hi");
postman.setNextRequest("Request");
counter++;
pm.environment.set("counter",counter);
console.log("Counter",counter);
}
The above scipts is throwing
TypeError | ClientArray.push is not a function.
Could someone please advice how to achieve this.
When you retrieve a value from an environment variable like you're doing:
ClientArray = pm.environment.get("ClientArray");
You're not getting an array, you're getting a string which is why you're getting that error. You need to treat the variable like a string, append the currentClientId much like you do for the counter. Something like:
var currentClientIds = pm.environment.get("ClientArray");
currentClientIds = currentClientIds + "," + currentClientId
When you're done appending i.e. out of your loop simply take the string and convert it to an array:
var currentClientIds = pm.environment.get("ClientArray");
var idsArr = curentClientIds.split(',');

how many items can a array handle node.js

I am trying to put objects to array based on txt file that has around 500.000 lines or more
I am using require('readline') to handle it, but the processing "pause" for yourself when achieve line 470000(e.g) without errors, warnings, notices...
this is examplo of my code ( the original code fill the dataRow object then it "pauses" when achieve line 411000):
let myList = [];
let lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filePath).pipe(iconv.decodeStream('latin1'))
});
lineReader.on('line', function (line) {
// here there are a lot more fields, but I have to cut off for this example
let dataRow = JSON.parse('{"Agencia_Cobranca":"","Aliquota_ICMS":""}');
myList.push(dataRow);
//this if is only to follow what is happen
if( myList.length %10000 == 0 || myList.length>420000) {
console.log(" myList executed: ",myList.length, ' - ', JSON.stringify( myList[myList.length-1] ).length, ' - ' ,new Date() );
}
}).on('close',function(){
console.log('finished');
process.exit(0);
});
I am using this command line to execute
node --max-old-space-size=8192 teste
Welll... this is the result, the screen just stay this way when achieve this line... never ends and without errors :(
Your stack/Ram is probably full and erroring out in a weird way. I would recommend if at all possible to make your program more memory efficient, do everything you need to do with a line as you read it and then discard it. Storing it all in memory is never going to be a solution.
In NodeJs (javascript too) maximum size of an array object is 2^32 -1. Just try to execute this in a nodejs application
console.log(new Array(4294967295))
try {
console.log(new Array(4294967296))
} catch(err){
console.log(err);
}
Consider using database if you work with that much data. Store it in a table then query the data you need to work with would be more efficient.

AngularJS e2e Testing: How To Get value of repeater().count()?

Problem
Calling repeater('#myTable tr','Rows').count(); returns a Future, not an integer. I need to get the integer value so I can confirm that an additional row was added to a table.
Code
it('should add a new user when save button is clicked',function()
{
showModal();
//here I'm trynig to store the row count of my table into a local variable.
//a future is returned who's 'value' field is undefined.
var memberCount = repeater('#memberTable tr','Member Rows').count();
//this outputs 'undefined'
console.log(memberCount.value);
input('editedMember.name').enter('John');
input('editedMember.grade').enter(5);
input('editedMember.ladderPosition').enter(3);
element('#saveMemberButton').click();
sleep(1);
expect(element(modalId).css('display')).toBe('none');
//here is where I want to do the comparison against the above stored memberCount
expect(repeater('#memberTable tr', 'Member Rows').count()).toBe(memberCount.value + 1);
});
Test Result
Chrome 25.0 e2e should add a new user when save button is clicked FAILED
expect repeater 'Member Rows ( #memberTable tr )' count toBe null
/Users/jgordon/learning/chessClub/web-app/test/e2e/scenarios.js:45:3: expected null but was 6
Chrome 25.0: Executed 2 of 2 (1 FAILED) (1 min 4.117 secs / 1 min 3.773 secs)
Drilling into the source code for Angularjs' e2e support reveals that you have to call execute() on the Future to have it populate its value. Also, when you call execute you have to provide a "done" function to the execute() otherwise Testacular will (oddly enough!) skip your test.
Code
var rowCountFuture = repeater('#memberTable tr','Member Rows').count();
rowCountFuture.execute(function(){
});
var memberCount = rowCountFuture.value;
While I'm jazzed to see this works, I'm concerned there may be some asynchronous bugs that could come out of this, also, I feel like this is a hack and not the right way to do it. Any ideas?
Based on the latest Protractor version:
it('should add a new user when save button is clicked', function() {
var memberCount;
element.all(by.repeater('#memberTable tr','Member Rows')).count().then(function(value) {
memberCount = value;
});
...
// then do all your entering user info, saving etc.
...
browser.refresh(); // or however you want to load new data
expect(element.all(by.repeater('#memberTable tr','Member Rows')).count()).toEqual(memberCount + 1);
});
I've run into the same issue, and have seen confusing results when testing value returned after calling execute(). I've found this method works more reliably:
var getCount = repeater('ul li').count();
getCount.execute(function(value) {
expect(value).toEqual(3);
});
You can do this most easily in the async promise returned by the locator
element.all(By.repeater 'thing in things').then(function(elements){
count = elements.length;
expect(count).toEqual(3);
});

Resources