I'm in a loop here and for each iteration I'm calling _checkExistingDefaultTimes to check if a record exists.
The problem is, the code in the loop is not executed until I'm outside the for loop.
Is there any way I can use a Promise so that it forces the .then code (pushing oOpeningTimes) before the loop finishes?
var oOpeningTimes = [];
for (var i = 0; i < numberOfDays; i++) {
this._checkExistingDefaultTimes(test.SiteInfo.SiteId,test.EffectiveDateFrom,
test.EffectiveDateTo)
.then(function (bResult) {
oOpeningTimes.push({
temporaryDate: oDate,
startTime1: oModelData[oWeekday].startTime1,
endTime1: oModelData[oWeekday].endTime1,
});
});
oStoreData.OpeningTimes = oOpeningTimes;
oModel.setData(oStoreData);
After the loop, no. The for-loop is a synchronous construct and the promise is async. What you need to do is wait until all of the promises generated in the loop are resolved before running your follow-on code. This is what Promise.all is for. You could do something like the following:
var oOpeningTimes = [];
var oPromises = [];
for (var i = 0; i < numberOfDays; i++) {
oPromises.push(this._checkExistingDefaultTimes(test.SiteInfo.SiteId,test.EffectiveDateFrom,
test.EffectiveDateTo)
.then(function (bResult) {
oOpeningTimes.push({
temporaryDate: oDate,
startTime1: oModelData[oWeekday].startTime1,
endTime1: oModelData[oWeekday].endTime1,
});
}));
Promise.all(oPromises).then(function() {
oStoreData.OpeningTimes = oOpeningTimes;
oModel.setData(oStoreData);
})
Related
I try to change an array of user in my mongodb from another collection.
this is the code:
phrases.find({albumID: tileid}).toArray(function(err, results) {
if (results.length > 0) {
for(var j = 0; j < results.length; j++)
{
for(var z = 0; z < o.Phrases.length; z++)
{
if(o.Phrases[z].id == results[j]._id)
{
o.Phrases.splice(z,1);
break;
}
}
}
}
});
console.log(o.Phrases);
.
.
.
after update the collection
When I do logs, I don't see the change being made.
If I do the logs in toArray blocks, I see the changes.
I read alot, And dont found solution only that toArray is async function but not how to change it or to use it.
Maybe there is another way to change the collection to the array.
thanks for helping.
I am using For loop to iterate over a table. When a certain condition is met against a row, I will break from for loop. But as per my code, FOR seems to run asynchronously causing iteration in parallel which I do not intend my program to do. Can someone help in working with this problem which I assume is due to promise resolution.
element.all(by.css('tbody tr')).then(function(rows){
for(var i = 1; i < (rows.length); i++) {
var count=0;
var pass=0;
//TEST VALUES BELOW
var appNameCreated="Test App 534";
//TEST VALUES ABOVE
console.log(i);
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).getText().then(function(appname){
console.log(i,appname);
if(appname==appNameCreated){
console.log(appname,appNameCreated,i);
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(6)')).getText().then(function(result){
console.log(result,i);
// if (result==data.resultSubmit){
if (result=="Activated"){
pass += 1;
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).element(by.css('a')).click().then(function(){
browser.sleep(4000);
});
element(by.id("btnTab3")).element(by.xpath('span')).click();
browser.wait(EC.visibilityOf(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr[1]/td[1]'))),15000); browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
element(by.id("button-basic")).click();
element.all(by.css('ul[class="dropdown-menu"]')).each(function(item1){
item1.element(by.css('li:nth-child(7)')).element(by.css('a')).click();
})
element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+i+']')).element(by.css('td:nth-child(6)')).getText().then(function(resultFin){
console.log(resultFin);
browser.actions().mouseMove(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)'))).perform();
expect(resultFin).toBe(data.resultFinal);
})
}
})
}
})
if(pass==1){
break;
}
}
})
You can use Array-like object's reduce() to iterate the rows and use Promise.reject() once the row meet your condition to break the loop.
Because you reject the promise, you should use Promise.catch() to capture it, and click the matched row to enter next page and do operations , then back to table page inside the catch()
let appName = 'Test App 534',
tbl = element(by.xpath(
'/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table')),
rows = tbl.all(by.css('tbody > tr'));
rows.reduce((initValue, row, rowIndex)=>{
return row.all(by.css('td:nth-child(1),td:nth-child(6)'))
.getText()
.then((txts)=>{
console.log('row ' +rowIndex+ ', txts: ' + txts)
if(txts[0] === appName && txts[1] === 'Activated') {
console.log('this is matched row');
// when the row meet the condition
// reject a promise with the row index of matched row.
// Promise.reject() will break out the loop
// and code will run into the following catch() section
return Promise.reject(rowIndex);
}
})
}, -1)
.catch((rowIndex)=>{
// use catch() to obtains the row index of matched row via
// Promise.reject(rowIndex) in previous rows.reduce()
console.log('matched row:' + rowIndex);
// click on matched row to enter next page
rows.get(rowIndex).element(by.css('td:nth-child(1) > a')).click();
browser.sleep(4000);
// do other operations and back to the table page
...
return rowIndex;
// still return the rowIndex for as argument for
// the following then() which we will check
// the status of matched row is still Activated
})
.then((rowIndex)=>{
console.log('matched row2:' + rowIndex);
console.log("Check matched row's status is still 'Activated'")
let status = rows.get(rowIndex).element(by.css('td:nth-child(6)')).getText();
expect(status).toEqual('Activated');
return browser.sleep(5000)
})
Update your code:
- change promise resolving using async ... await
- change var to let, const
- counting in a loop should begin from 0 instead of 1
- change == to ===
- .each() does not work properly with async operations as click()
Questions:
- from where you take data.resultSubmit ?
const rows = await element.all(by.css('tbody tr'));
const appNameCreated = "Test App 534";
let count = 0;
let pass = 0;
for (let i = 0; i < rows.length; i++) {
console.log('Index is ', i);
const appname = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).getText();
console.log('App name for current loop is ', appname);
if(appname === appNameCreated) {
console.log('App name is the same as created app name for loop with index ', i);
const result = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(6)')).getText();
console.log('Result for current run is ' result);
if (result === data.resultSubmit && result === "Activated") {
pass += 1;
await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)')).element(by.css('a')).click();
await browser.sleep(4000);
});
await element(by.id("btnTab3")).element(by.xpath('span')).click();
await browser.wait(EC.visibilityOf(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr[1]/td[1]'))),15000);
await browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
await browser.wait(EC.visibilityOf(element(by.id("button-basic"))),15000);
await element(by.id("button-basic")).click();
const menus = await element.all(by.css('ul[class="dropdown-menu"]'));
const amount = await menus.count();
for (let i = 0; i < amount; i++) {
const item = await menus.get(i);
await item.element(by.css('li:nth-child(7)')).element(by.css('a')).click();
}
const resultFin = await element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+i+']')).element(by.css('td:nth-child(6)')).getText();
console.log('resultFin is ', resultFin);
await browser.actions().mouseMove(element(by.xpath('/html/body/gft-root/section/div[2]/app-onboard-list/div[4]/div[3]/table/tbody/tr['+ i +']')).element(by.css('td:nth-child(1)'))).perform();
expect(resultFin).toBe(data.resultFinal);
})
}
})
}
})
if(pass ===1 ){
break;
}
}
})
I have tried to remove as much mistakes as I can. Your code is bad because you don't split this BIG amount of "What a hell is there???" to smaller functions.
I want to generate multiple protractor tests using promise value with loop concept, Please give me a solution .
var rowNumber = function call;
rowNumber.then(function(resultTC){`enter code here`
for (var i = 1; i < parseInt(resultTC); i++) {
it('should work for ' + i, function (done) {
console.log("welcome");
});
};
});
You can generate more tests passing different data with data parametrization, I don't know why You need looping.
I was wondering whether it's possible to wait for a callback before continuing a process.
I'm using a library that handles a future internally and then if it was successful, does a callback, otherwise handles the error internally with no callback.
Now I'm trying to use this library to create an instance, then fill it with random test data and then update that entity.
Map generateRandomizedInstance() {
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
return result2;
})
});
}
This would be fine if I'm only creating one entity and updating it once, but I want to create lots of random data:
ButtonElement b = querySelector("button.create")..onClick.listen((e){
for (int i = 0; i < 500; i++) {
generateRandomizedInstance();
}
});
It doesn't take long for this code to crash spectacularly as the callbacks aren't coming back fast enough.
I've tried changing the method signature to
generateRandomizedInstance() async {
and then doing:
for (int i = 0; i < 500; i++) {
print(await generateRandomizedInstance());
}
but that await syntax seems to be invalid and I'm not completely sure how to wrap that callback code in some kind of future that I can wait for the callback to come back before continuing to the next iteration of the loop.
I've tried a while loop at the end of generateRandomizedInstance that waits for a result variable to not be null, but that kills the browser and seeing as I'm not always getting a callback, in some cases it could cause an infinite loop.
Any ideas / suggestion on how to pause that for loop while waiting for the callback?
This should do what you want:
Future<Map> generateRandomizedInstance() {
Completer<Map> c = new Completer<Map>();
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
c.complete(result2);
})
});
return c.future;
}
ButtonElement b = querySelector("button.create")..onClick.listen((e) async {
for (int i = 0; i < 500; i++) {
await generateRandomizedInstance();
}
});
I would like to know how can I get the data from mongodb in Template.templatename.rendered function. I tried click event on other template and it's all working fine and return the results i wanted. But what I need is to rendered the chart on load. But I could not get any data from the mongodb.
//poll.js
var drawPollChart = function(){
//returns data on other template methods except for
//Template.templatename.rendered
var dist = getDistinctQuestionId();
alert('dist:'+dist);
var data_x =[];
for(var i=0; i< 1; i++)
{
var count = getDataCount(dist[i]);
var uniq = getDistinctResponseBucket(dist[i]);
for(var j=0; j<uniq.length; j++)
{
//alert('data:' + count[uniq[j]] + ", label:" + uniq[j]);
data_x.push({
data : count[uniq[j]],
label: uniq[j]
});
}
}
Template.pollChart.rendered = function() {
//can't draw a thing cause can't get any data from mongodb
drawPollChart();
};
Help please? Thanks in advance.
Just because the template is rendered doesn't mean the DB is connected.
Use Meteor.status().status to detect the state of the connection. For example you could wait to render the pollChart-template at all until Meteor.status().status === 'connected'.